[
  {
    "path": ".gitignore",
    "content": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n.idea/\nwhitebox/WBT/\n**/*.tar.xz\n**/*.xml\n**/.access^\nwhitebox/testdata/breached.tif\nwhitebox/testdata/flow_accum.tif\nwhitebox/testdata/smoothed.tif\nwhitebox/whitebox_tools\ndev/\n.vscode/\n_build/\ntemp/\nWhiteboxTools_win_amd64.zip\n**/*.db\n**/*.db:encryptable\nWhiteboxTools.pyt.zip\n**/*.lock\n**/*.aux.xml\n**/*.tfw\n**/*.tif.ovr\n**/*.CPG\n__MACOSX/\nwhitebox_tools-v*.exe\nWBT/img/._*\n\n\n# C extensions\n*.so\n\n# Distribution / packaging\n.Python\nenv/\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# PyInstaller\n#  Usually these files are written by a python script from a template\n#  before PyInstaller builds the exe, so as to inject date/other infos into it.\n*.manifest\n*.spec\n\n# Installer logs\npip-log.txt\npip-delete-this-directory.txt\n\n# Unit test / coverage reports\nhtmlcov/\n.tox/\n.coverage\n.coverage.*\n.cache\nnosetests.xml\ncoverage.xml\n*.cover\n.hypothesis/\n.pytest_cache/\n\n# Translations\n*.mo\n*.pot\n\n# Django stuff:\n*.log\nlocal_settings.py\n\n# Flask stuff:\ninstance/\n.webassets-cache\n\n# Scrapy stuff:\n.scrapy\n\n# Sphinx documentation\ndocs/_build/\n\n# PyBuilder\ntarget/\n\n# Jupyter Notebook\n.ipynb_checkpoints\nexamples/.ipynb_checkpoints\n\n# pyenv\n.python-version\n\n# celery beat schedule file\ncelerybeat-schedule\n\n# SageMath parsed files\n*.sage.py\n\n# dotenv\n.env\n\n# virtualenv\n.venv\nvenv/\nENV/\n\n# Spyder project settings\n.spyderproject\n.spyproject\n\n# Rope project settings\n.ropeproject\n\n# mkdocs documentation\n/site\n\n# mypy\n.mypy_cache/\nWBT/img/.DS_Store\nWBT/whitebox_runner.exe\nWBT/settings.json\n"
  },
  {
    "path": ".pre-commit-config.yaml",
    "content": "repos:\n  - repo: https://github.com/pre-commit/pre-commit-hooks\n    rev: v6.0.0\n    hooks:\n      - id: check-toml\n      - id: check-yaml\n      # - id: end-of-file-fixer\n      #   types: [python]\n      # - id: trailing-whitespace\n      # - id: requirements-txt-fixer\n      # - id: check-added-large-files\n      #   args: [\"--maxkb=500\"]\n\n  # - repo: https://github.com/psf/black\n  #   rev: 24.10.0\n  #   hooks:\n  #     - id: black-jupyter\n\n  # - repo: https://github.com/codespell-project/codespell\n  #   rev: v2.3.0\n  #   hooks:\n  #     - id: codespell\n  #       args:\n  #         [\n  #           \"--ignore-words-list=aci,acount,acounts,fallow,ges,hart,hist,nd,ned,ois,wqs,watermask,tre\",\n  #           \"--skip=*.csv,*.geojson,*.json,*.yml*.js,*.html,*cff,*.pdf\",\n  #         ]\n\n  # - repo: https://github.com/kynan/nbstripout\n  #   rev: 0.8.0\n  #   hooks:\n  #     - id: nbstripout\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2019 Qiusheng Wu\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# WhiteboxTools-ArcGIS\n\n[![docs](https://img.shields.io/badge/whitebox-docs-brightgreen.svg)](https://www.whiteboxgeo.com/manual/wbt_book/preface.html)\n[![ArcGIS](https://img.shields.io/badge/whitebox-ArcGIS-brightgreen.svg)](https://github.com/opengeos/WhiteboxTools-ArcGIS)\n[![python](https://img.shields.io/badge/whitebox-Python-blue.svg)](https://github.com/opengeos/whitebox-python)\n[![R](https://img.shields.io/badge/whitebox-R-green.svg)](https://github.com/opengeos/whiteboxR)\n[![QGIS](https://img.shields.io/badge/whitebox-QGIS-orange.svg)](https://www.whiteboxgeo.com/manual/wbt_book/qgis_plugin.html)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Donate](https://img.shields.io/badge/Donate-Buy%20me%20a%20coffee-yellowgreen.svg)](https://www.buymeacoffee.com/giswqs)\n\nArcGIS Python Toolbox for WhiteboxTools.\n\nThis repository is related to the **ArcGIS Python Toolbox for WhiteboxTools**, which is an ArcGIS frontend of a stand-alone executable command-line program called **[WhiteboxTools](https://github.com/jblindsay/whitebox-tools)**.\n\n![Note](https://i.imgur.com/Ic8BA7C.png) **Important Note:** This toolbox only supports **ArcGIS Pro and ArcGIS 10.6 or newer**. Don't waste your time trying it on ArcGIS 10.5 or older versions. \n\n* Authors: John Lindsay (<https://jblindsay.github.io/ghrg/index.html>)\n* Contributors: Qiusheng Wu (<https://wetlands.io>)\n* WhiteboxTools: <https://github.com/jblindsay/whitebox-tools>\n* User Manual: <https://www.whiteboxgeo.com/manual/wbt_book/preface.html>\n* WhiteboxTools-ArcGIS: <https://github.com/opengeos/WhiteboxTools-ArcGIS>\n* WhiteboxTools-Python: <https://github.com/opengeos/whitebox>\n* WhiteboxTools-Jupyter: <https://github.com/opengeos/whiteboxgui>\n* WhiteboxTools-R: <https://github.com/opengeos/whiteboxR>\n* Free software: [MIT license](https://opensource.org/licenses/MIT)\n\n**Contents**\n\n- [WhiteboxTools-ArcGIS](#whiteboxtools-arcgis)\n  - [Description](#description)\n  - [Installation](#installation)\n    - [Step 1: Download the toolbox](#step-1-download-the-toolbox)\n    - [Step 2: Connect to the toolbox](#step-2-connect-to-the-toolbox)\n  - [Usage](#usage)\n  - [Tutorials](#tutorials)\n  - [Available Tools](#available-tools)\n  - [Supported Data Formats](#supported-data-formats)\n  - [Contributing](#contributing)\n  - [License](#license)\n  - [Reporting Bugs](#reporting-bugs)\n  - [Toolbox Screenshots](#toolbox-screenshots)\n\n## Description\n\n**WhiteboxTools-ArcGIS** is an ArcGIS Python Toolbox for **WhiteboxTools**, an advanced geospatial data analysis platform developed by Prof. John Lindsay ([webpage](https://jblindsay.github.io/ghrg/index.html); [jblindsay](https://github.com/jblindsay)) at the University of Guelph's [Geomorphometry and Hydrogeomatics Research Group](https://jblindsay.github.io/ghrg/index.html). *WhiteboxTools* can be used to perform common geographical information systems (GIS) analysis operations, such as cost-distance analysis, distance buffering, and raster reclassification. Remote sensing and image processing tasks include image enhancement (e.g. panchromatic sharpening, contrast adjustments), image mosaicing, numerous filtering operations, simple classification (k-means), and common image transformations. *WhiteboxTools* also contains advanced tooling for spatial hydrological analysis (e.g. flow-accumulation, watershed delineation, stream network analysis, sink removal), terrain analysis (e.g. common terrain indices such as slope, curvatures, wetness index, hillshading; hypsometric analysis; multi-scale topographic position analysis), and LiDAR data processing. LiDAR point clouds can be interrogated (LidarInfo, LidarHistogram), segmented, tiled and joined, analyized for outliers, interpolated to rasters (DEMs, intensity images), and ground-points can be classified or filtered. *WhiteboxTools* is not a cartographic or spatial data visualization package; instead it is meant to serve as an analytical backend for other data visualization software, mainly GIS. Suggested citation: Lindsay, J. B. (2016). Whitebox GAT: A case study in geomorphometric analysis. _Computers & Geosciences_, 95, 75-84. doi:[10.1016/j.cageo.2016.07.003](http://dx.doi.org/10.1016/j.cageo.2016.07.003).\n\n## Installation\n\n### Step 1: Download the toolbox\n\n1. Click the green button (**[Clone or download](https://gishub.org/whitebox-arcgis-download)**) on the upper-right corner of this page to download the toolbox as a zip file.\n\n    ![](https://i.imgur.com/2xQkxCY.png)\n\n2. Depcompress the downloaded zip file.\n\n### Step 2: Connect to the toolbox\n\n1. Navigate to the **Folder Connections** node in the catalog window tree.\n\n2. Right-click the node and choose **Connect To Folder**.\n\n    ![](https://i.imgur.com/uKK1Yel.png)\n\n3. Type the path or navigate to the **WhiteboxTools-ArcGIS** folder and click **OK**.\n\n4. Browse into the toolbox and start using its tools.\n\n    ![](https://i.imgur.com/JcdNBnt.png)\n\n## Usage\n\nOpen any tool within the toolbox and start using it. Check out the [WhiteboxTools User Mannual](https://www.whiteboxgeo.com/manual/wbt_book/) for more detailed help documentation of each tool.\n\n![](https://i.imgur.com/4c9RLZY.png)\n\n## Tutorials\n\n[Introducing WhiteboxTools frontends (Python, Jupyter, ArcGIS, R)](https://youtu.be/cv33vkpwta0)\n\n[![](https://img.youtube.com/vi/cv33vkpwta0/0.jpg)](https://youtu.be/cv33vkpwta0)\n\n## Available Tools\n\nThe **[WhiteboxTools](https://github.com/jblindsay/whitebox-tools)** library currently contains **468** tools, which are each grouped based on their main function into one of the following categories: Data Tools, GIS Analysis, Hydrological Analysis, Image Analysis, LiDAR Analysis, Mathematical and Statistical Analysis, Stream Network Analysis, and Terrain Analysis. For a listing of available tools, complete with documentation and usage details, please see the [WhiteboxTools User Manual](https://www.whiteboxgeo.com/manual/wbt_book/available_tools/index.html).\n\n## Supported Data Formats\n\nThe **WhiteboxTools** library can currently support read/writing raster data in [*Whitebox GAT*](http://www.uoguelph.ca/~hydrogeo/Whitebox/), GeoTIFF, ESRI (ArcGIS) ASCII and binary (.flt & .hdr), GRASS GIS, Idrisi, SAGA GIS (binary and ASCII), and Surfer 7 data formats. The library is primarily tested using Whitebox raster data sets and if you encounter issues when reading/writing data in other formats, you should report the [issue](https://github.com/jblindsay/whitebox-tools/issues). Please note that there are no plans to incorporate third-party libraries, like [GDAL](http://www.gdal.org), in the project given the design goal of keeping a pure (or as close as possible) Rust codebase.\n\nAt present, there is limited ability in *WhiteboxTools* to read vector geospatial data. Support for Shapefile (and other common vector formats) will be enhanced within the library soon.\n\nLiDAR data can be read/written in the common [LAS](https://www.asprs.org/committee-general/laser-las-file-format-exchange-activities.html) data format. *WhiteboxTools* can read and write LAS files that have been compressed (zipped with a .zip extension) using the common DEFLATE algorithm. Note that only LAS file should be contained within a zipped archive file. The compressed LiDAR format LAZ and ESRI LiDAR format are not currently supported by the library.\n\n## Contributing\n\nIf you would like to contribute to the project as a developer, follow these instructions to get started:\n\n1. Fork the WhiteboxTools-ArcGIS repository (<https://github.com/opengeos/WhiteboxTools-ArcGIS>)\n2. Create your feature branch (git checkout -b my-new-feature)\n3. Commit your changes (git commit -am 'Add some feature')\n4. Push to the branch (git push origin my-new-feature)\n5. Create a new Pull Request\n\nUnless explicitly stated otherwise, any contribution intentionally submitted for inclusion in the work shall be licensed as the [MIT license](https://opensource.org/licenses/MIT) without any additional terms or conditions.\n\n## License\n\nThe **ArcGIS Toolbox for WhiteboxTools** is distributed under the [MIT license](https://opensource.org/licenses/MIT), a permissive open-source (free software) license.\n\n## Reporting Bugs\n\n**ArcGIS Toolbox for WhiteboxTools** is distributed as is and without warranty of suitability for application. If you encounter flaws with the software (i.e. bugs) please report the issue. Providing a detailed description of the conditions under which the bug occurred will help to identify the bug. *Use the [Issues tracker](https://github.com/opengeos/WhiteboxTools-ArcGIS/issues) on GitHub to report issues with the software and to request feature enchancements.* Please do not email Dr. Qiusheng Wu or Dr. John Lindsay directly with bugs.\n\n## Toolbox Screenshots\n\n![Toolbox-1](screenshots/Toolbox-1.png)\n![Toolbox-2](screenshots/Toolbox-2.png)\n![Toolbox-3](screenshots/Toolbox-3.png)"
  },
  {
    "path": "WBT/LICENSE.txt",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2017-2021 John Lindsay\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "WBT/PRE/WhiteboxTools.py",
    "content": "import arcpy\nimport os\nimport webbrowser\nfrom WBT.whitebox_tools import WhiteboxTools\nif sys.version_info < (3, 0):\n    from StringIO import StringIO\nelse:\n    from io import StringIO\n\nwbt = WhiteboxTools()\ntool_labels = []\n\ntool_labels.append(\"Absolute Value\")\ntool_labels.append(\"Accumulation Curvature\")\ntool_labels.append(\"Adaptive Filter\")\ntool_labels.append(\"Add\")\ntool_labels.append(\"Add Point Coordinates To Table\")\ntool_labels.append(\"Aggregate Raster\")\ntool_labels.append(\"And\")\ntool_labels.append(\"Anova\")\ntool_labels.append(\"Arc Cos\")\ntool_labels.append(\"Arc Sin\")\ntool_labels.append(\"Arc Tan\")\ntool_labels.append(\"Arcosh\")\ntool_labels.append(\"Arsinh\")\ntool_labels.append(\"Artanh\")\ntool_labels.append(\"Ascii To Las\")\ntool_labels.append(\"Aspect\")\ntool_labels.append(\"Assess Route\")\ntool_labels.append(\"Atan2\")\ntool_labels.append(\"Attribute Correlation\")\ntool_labels.append(\"Attribute Correlation Neighbourhood Analysis\")\ntool_labels.append(\"Attribute Histogram\")\ntool_labels.append(\"Attribute Scattergram\")\ntool_labels.append(\"Average Flowpath Slope\")\ntool_labels.append(\"Average Normal Vector Angular Deviation\")\ntool_labels.append(\"Average Overlay\")\ntool_labels.append(\"Average Upslope Flowpath Length\")\ntool_labels.append(\"Balance Contrast Enhancement\")\ntool_labels.append(\"Basins\")\ntool_labels.append(\"Bilateral Filter\")\ntool_labels.append(\"Block Maximum Gridding\")\ntool_labels.append(\"Block Minimum Gridding\")\ntool_labels.append(\"Boundary Shape Complexity\")\ntool_labels.append(\"Breach Depressions\")\ntool_labels.append(\"Breach Depressions Least Cost\")\ntool_labels.append(\"Breach Single Cell Pits\")\ntool_labels.append(\"Breakline Mapping\")\ntool_labels.append(\"Buffer Raster\")\ntool_labels.append(\"Burn Streams At Roads\")\ntool_labels.append(\"Canny Edge Detection\")\ntool_labels.append(\"Ceil\")\ntool_labels.append(\"Centroid\")\ntool_labels.append(\"Centroid Vector\")\ntool_labels.append(\"Change Vector Analysis\")\ntool_labels.append(\"Circular Variance Of Aspect\")\ntool_labels.append(\"Classify Buildings In Lidar\")\ntool_labels.append(\"Classify Lidar\")\ntool_labels.append(\"Classify Overlap Points\")\ntool_labels.append(\"Clean Vector\")\ntool_labels.append(\"Clip\")\ntool_labels.append(\"Clip Lidar To Polygon\")\ntool_labels.append(\"Clip Raster To Polygon\")\ntool_labels.append(\"Closing\")\ntool_labels.append(\"Clump\")\ntool_labels.append(\"Colourize Based On Class\")\ntool_labels.append(\"Colourize Based On Point Returns\")\ntool_labels.append(\"Compactness Ratio\")\ntool_labels.append(\"Conditional Evaluation\")\ntool_labels.append(\"Conditioned Latin Hypercube\")\ntool_labels.append(\"Conservative Smoothing Filter\")\ntool_labels.append(\"Construct Vector Tin\")\ntool_labels.append(\"Contours From Points\")\ntool_labels.append(\"Contours From Raster\")\ntool_labels.append(\"Convert Nodata To Zero\")\ntool_labels.append(\"Convert Raster Format\")\ntool_labels.append(\"Corner Detection\")\ntool_labels.append(\"Correct Vignetting\")\ntool_labels.append(\"Cos\")\ntool_labels.append(\"Cosh\")\ntool_labels.append(\"Cost Allocation\")\ntool_labels.append(\"Cost Distance\")\ntool_labels.append(\"Cost Pathway\")\ntool_labels.append(\"Count If\")\ntool_labels.append(\"Create Colour Composite\")\ntool_labels.append(\"Create Hexagonal Vector Grid\")\ntool_labels.append(\"Create Plane\")\ntool_labels.append(\"Create Rectangular Vector Grid\")\ntool_labels.append(\"Crispness Index\")\ntool_labels.append(\"Cross Tabulation\")\ntool_labels.append(\"Csv Points To Vector\")\ntool_labels.append(\"Cumulative Distribution\")\ntool_labels.append(\"Curvedness\")\ntool_labels.append(\"D Inf Flow Accumulation\")\ntool_labels.append(\"D Inf Mass Flux\")\ntool_labels.append(\"D Inf Pointer\")\ntool_labels.append(\"D8 Flow Accumulation\")\ntool_labels.append(\"D8 Mass Flux\")\ntool_labels.append(\"D8 Pointer\")\ntool_labels.append(\"Dbscan\")\ntool_labels.append(\"Decrement\")\ntool_labels.append(\"Dem Void Filling\")\ntool_labels.append(\"Depth In Sink\")\ntool_labels.append(\"Depth To Water\")\ntool_labels.append(\"Dev From Mean Elev\")\ntool_labels.append(\"Diff From Mean Elev\")\ntool_labels.append(\"Diff Of Gaussian Filter\")\ntool_labels.append(\"Difference\")\ntool_labels.append(\"Difference Curvature\")\ntool_labels.append(\"Direct Decorrelation Stretch\")\ntool_labels.append(\"Directional Relief\")\ntool_labels.append(\"Dissolve\")\ntool_labels.append(\"Distance To Outlet\")\ntool_labels.append(\"Diversity Filter\")\ntool_labels.append(\"Divide\")\ntool_labels.append(\"Downslope Distance To Stream\")\ntool_labels.append(\"Downslope Flowpath Length\")\ntool_labels.append(\"Downslope Index\")\ntool_labels.append(\"Edge Contamination\")\ntool_labels.append(\"Edge Density\")\ntool_labels.append(\"Edge Preserving Mean Filter\")\ntool_labels.append(\"Edge Proportion\")\ntool_labels.append(\"Elev Above Pit\")\ntool_labels.append(\"Elev Percentile\")\ntool_labels.append(\"Elev Relative To Min Max\")\ntool_labels.append(\"Elev Relative To Watershed Min Max\")\ntool_labels.append(\"Elevation Above Stream\")\ntool_labels.append(\"Elevation Above Stream Euclidean\")\ntool_labels.append(\"Eliminate Coincident Points\")\ntool_labels.append(\"Elongation Ratio\")\ntool_labels.append(\"Embankment Mapping\")\ntool_labels.append(\"Emboss Filter\")\ntool_labels.append(\"Equal To\")\ntool_labels.append(\"Erase\")\ntool_labels.append(\"Erase Polygon From Lidar\")\ntool_labels.append(\"Erase Polygon From Raster\")\ntool_labels.append(\"Euclidean Allocation\")\ntool_labels.append(\"Euclidean Distance\")\ntool_labels.append(\"Evaluate Training Sites\")\ntool_labels.append(\"Exp\")\ntool_labels.append(\"Exp2\")\ntool_labels.append(\"Export Table To Csv\")\ntool_labels.append(\"Exposure Towards Wind Flux\")\ntool_labels.append(\"Extend Vector Lines\")\ntool_labels.append(\"Extract Nodes\")\ntool_labels.append(\"Extract Raster Values At Points\")\ntool_labels.append(\"Extract Streams\")\ntool_labels.append(\"Extract Valleys\")\ntool_labels.append(\"Farthest Channel Head\")\ntool_labels.append(\"Fast Almost Gaussian Filter\")\ntool_labels.append(\"Fd8 Flow Accumulation\")\ntool_labels.append(\"Fd8 Pointer\")\ntool_labels.append(\"Feature Preserving Smoothing\")\ntool_labels.append(\"Fetch Analysis\")\ntool_labels.append(\"Fill Burn\")\ntool_labels.append(\"Fill Depressions\")\ntool_labels.append(\"Fill Depressions Planchon And Darboux\")\ntool_labels.append(\"Fill Depressions Wang And Liu\")\ntool_labels.append(\"Fill Missing Data\")\ntool_labels.append(\"Fill Single Cell Pits\")\ntool_labels.append(\"Filter Lidar\")\ntool_labels.append(\"Filter Lidar Classes\")\ntool_labels.append(\"Filter Lidar Scan Angles\")\ntool_labels.append(\"Filter Raster Features By Area\")\ntool_labels.append(\"Find Flightline Edge Points\")\ntool_labels.append(\"Find Lowest Or Highest Points\")\ntool_labels.append(\"Find Main Stem\")\ntool_labels.append(\"Find No Flow Cells\")\ntool_labels.append(\"Find Parallel Flow\")\ntool_labels.append(\"Find Patch Or Class Edge Cells\")\ntool_labels.append(\"Find Ridges\")\ntool_labels.append(\"Fix Dangling Arcs\")\ntool_labels.append(\"Flatten Lakes\")\ntool_labels.append(\"Flightline Overlap\")\ntool_labels.append(\"Flip Image\")\ntool_labels.append(\"Flood Order\")\ntool_labels.append(\"Floor\")\ntool_labels.append(\"Flow Accumulation Full Workflow\")\ntool_labels.append(\"Flow Length Diff\")\ntool_labels.append(\"Gamma Correction\")\ntool_labels.append(\"Gaussian Contrast Stretch\")\ntool_labels.append(\"Gaussian Curvature\")\ntool_labels.append(\"Gaussian Filter\")\ntool_labels.append(\"Gaussian Scale Space\")\ntool_labels.append(\"Generalize Classified Raster\")\ntool_labels.append(\"Generalize With Similarity\")\ntool_labels.append(\"Generating Function\")\ntool_labels.append(\"Geomorphons\")\ntool_labels.append(\"Greater Than\")\ntool_labels.append(\"Hack Stream Order\")\ntool_labels.append(\"Heat Map\")\ntool_labels.append(\"Height Above Ground\")\ntool_labels.append(\"High Pass Bilateral Filter\")\ntool_labels.append(\"High Pass Filter\")\ntool_labels.append(\"High Pass Median Filter\")\ntool_labels.append(\"Highest Position\")\ntool_labels.append(\"Hillshade\")\ntool_labels.append(\"Hillslopes\")\ntool_labels.append(\"Histogram Equalization\")\ntool_labels.append(\"Histogram Matching\")\ntool_labels.append(\"Histogram Matching Two Images\")\ntool_labels.append(\"Hole Proportion\")\ntool_labels.append(\"Horizon Angle\")\ntool_labels.append(\"Horizontal Excess Curvature\")\ntool_labels.append(\"Horton Stream Order\")\ntool_labels.append(\"Hydrologic Connectivity\")\ntool_labels.append(\"Hypsometric Analysis\")\ntool_labels.append(\"Hypsometrically Tinted Hillshade\")\ntool_labels.append(\"Idw Interpolation\")\ntool_labels.append(\"Ihs To Rgb\")\ntool_labels.append(\"Image Autocorrelation\")\ntool_labels.append(\"Image Correlation\")\ntool_labels.append(\"Image Correlation Neighbourhood Analysis\")\ntool_labels.append(\"Image Regression\")\ntool_labels.append(\"Image Segmentation\")\ntool_labels.append(\"Image Slider\")\ntool_labels.append(\"Image Stack Profile\")\ntool_labels.append(\"Impoundment Size Index\")\ntool_labels.append(\"In Place Add\")\ntool_labels.append(\"In Place Divide\")\ntool_labels.append(\"In Place Multiply\")\ntool_labels.append(\"In Place Subtract\")\ntool_labels.append(\"Increment\")\ntool_labels.append(\"Individual Tree Detection\")\ntool_labels.append(\"Insert Dams\")\ntool_labels.append(\"Install Wb Extension\")\ntool_labels.append(\"Integer Division\")\ntool_labels.append(\"Integral Image\")\ntool_labels.append(\"Intersect\")\ntool_labels.append(\"Inverse Pca\")\ntool_labels.append(\"Is No Data\")\ntool_labels.append(\"Isobasins\")\ntool_labels.append(\"Jenson Snap Pour Points\")\ntool_labels.append(\"Join Tables\")\ntool_labels.append(\"K Means Clustering\")\ntool_labels.append(\"K Nearest Mean Filter\")\ntool_labels.append(\"Kappa Index\")\ntool_labels.append(\"Knn Classification\")\ntool_labels.append(\"Knn Regression\")\ntool_labels.append(\"Ks Test For Normality\")\ntool_labels.append(\"Laplacian Filter\")\ntool_labels.append(\"Laplacian Of Gaussian Filter\")\ntool_labels.append(\"Las To Ascii\")\ntool_labels.append(\"Las To Laz\")\ntool_labels.append(\"Las To Multipoint Shapefile\")\ntool_labels.append(\"Las To Shapefile\")\ntool_labels.append(\"Las To Zlidar\")\ntool_labels.append(\"Launch Wb Runner\")\ntool_labels.append(\"Layer Footprint\")\ntool_labels.append(\"Laz To Las\")\ntool_labels.append(\"Lee Sigma Filter\")\ntool_labels.append(\"Length Of Upstream Channels\")\ntool_labels.append(\"Less Than\")\ntool_labels.append(\"Lidar Block Maximum\")\ntool_labels.append(\"Lidar Block Minimum\")\ntool_labels.append(\"Lidar Classify Subset\")\ntool_labels.append(\"Lidar Colourize\")\ntool_labels.append(\"Lidar Contour\")\ntool_labels.append(\"Lidar Digital Surface Model\")\ntool_labels.append(\"Lidar Eigenvalue Features\")\ntool_labels.append(\"Lidar Elevation Slice\")\ntool_labels.append(\"Lidar Ground Point Filter\")\ntool_labels.append(\"Lidar Hex Binning\")\ntool_labels.append(\"Lidar Hillshade\")\ntool_labels.append(\"Lidar Histogram\")\ntool_labels.append(\"Lidar Idw Interpolation\")\ntool_labels.append(\"Lidar Info\")\ntool_labels.append(\"Lidar Join\")\ntool_labels.append(\"Lidar Kappa Index\")\ntool_labels.append(\"Lidar Nearest Neighbour Gridding\")\ntool_labels.append(\"Lidar Point Density\")\ntool_labels.append(\"Lidar Point Return Analysis\")\ntool_labels.append(\"Lidar Point Stats\")\ntool_labels.append(\"Lidar Ransac Planes\")\ntool_labels.append(\"Lidar Rbf Interpolation\")\ntool_labels.append(\"Lidar Remove Duplicates\")\ntool_labels.append(\"Lidar Remove Outliers\")\ntool_labels.append(\"Lidar Rooftop Analysis\")\ntool_labels.append(\"Lidar Segmentation\")\ntool_labels.append(\"Lidar Segmentation Based Filter\")\ntool_labels.append(\"Lidar Shift\")\ntool_labels.append(\"Lidar Sibson Interpolation\")\ntool_labels.append(\"Lidar Thin\")\ntool_labels.append(\"Lidar Thin High Density\")\ntool_labels.append(\"Lidar Tile\")\ntool_labels.append(\"Lidar Tile Footprint\")\ntool_labels.append(\"Lidar Tin Gridding\")\ntool_labels.append(\"Lidar Tophat Transform\")\ntool_labels.append(\"Line Detection Filter\")\ntool_labels.append(\"Line Intersections\")\ntool_labels.append(\"Line Thinning\")\ntool_labels.append(\"Linearity Index\")\ntool_labels.append(\"Lines To Polygons\")\ntool_labels.append(\"List Unique Values\")\ntool_labels.append(\"List Unique Values Raster\")\ntool_labels.append(\"Ln\")\ntool_labels.append(\"Local Hypsometric Analysis\")\ntool_labels.append(\"Local Quadratic Regression\")\ntool_labels.append(\"Log10\")\ntool_labels.append(\"Log2\")\ntool_labels.append(\"Logistic Regression\")\ntool_labels.append(\"Long Profile\")\ntool_labels.append(\"Long Profile From Points\")\ntool_labels.append(\"Longest Flowpath\")\ntool_labels.append(\"Low Points On Headwater Divides\")\ntool_labels.append(\"Lowest Position\")\ntool_labels.append(\"Majority Filter\")\ntool_labels.append(\"Map Off Terrain Objects\")\ntool_labels.append(\"Max\")\ntool_labels.append(\"Max Absolute Overlay\")\ntool_labels.append(\"Max Anisotropy Dev\")\ntool_labels.append(\"Max Anisotropy Dev Signature\")\ntool_labels.append(\"Max Branch Length\")\ntool_labels.append(\"Max Difference From Mean\")\ntool_labels.append(\"Max Downslope Elev Change\")\ntool_labels.append(\"Max Elev Dev Signature\")\ntool_labels.append(\"Max Elevation Deviation\")\ntool_labels.append(\"Max Overlay\")\ntool_labels.append(\"Max Upslope Elev Change\")\ntool_labels.append(\"Max Upslope Flowpath Length\")\ntool_labels.append(\"Max Upslope Value\")\ntool_labels.append(\"Maximal Curvature\")\ntool_labels.append(\"Maximum Filter\")\ntool_labels.append(\"Md Inf Flow Accumulation\")\ntool_labels.append(\"Mean Curvature\")\ntool_labels.append(\"Mean Filter\")\ntool_labels.append(\"Median Filter\")\ntool_labels.append(\"Medoid\")\ntool_labels.append(\"Merge Line Segments\")\ntool_labels.append(\"Merge Table With Csv\")\ntool_labels.append(\"Merge Vectors\")\ntool_labels.append(\"Min\")\ntool_labels.append(\"Min Absolute Overlay\")\ntool_labels.append(\"Min Dist Classification\")\ntool_labels.append(\"Min Downslope Elev Change\")\ntool_labels.append(\"Min Max Contrast Stretch\")\ntool_labels.append(\"Min Overlay\")\ntool_labels.append(\"Minimal Curvature\")\ntool_labels.append(\"Minimum Bounding Box\")\ntool_labels.append(\"Minimum Bounding Circle\")\ntool_labels.append(\"Minimum Bounding Envelope\")\ntool_labels.append(\"Minimum Convex Hull\")\ntool_labels.append(\"Minimum Filter\")\ntool_labels.append(\"Modified K Means Clustering\")\ntool_labels.append(\"Modify Lidar\")\ntool_labels.append(\"Modify No Data Value\")\ntool_labels.append(\"Modulo\")\ntool_labels.append(\"Mosaic\")\ntool_labels.append(\"Mosaic With Feathering\")\ntool_labels.append(\"Multi Part To Single Part\")\ntool_labels.append(\"Multidirectional Hillshade\")\ntool_labels.append(\"Multiply\")\ntool_labels.append(\"Multiply Overlay\")\ntool_labels.append(\"Multiscale Curvatures\")\ntool_labels.append(\"Multiscale Elevation Percentile\")\ntool_labels.append(\"Multiscale Roughness\")\ntool_labels.append(\"Multiscale Roughness Signature\")\ntool_labels.append(\"Multiscale Std Dev Normals\")\ntool_labels.append(\"Multiscale Std Dev Normals Signature\")\ntool_labels.append(\"Multiscale Topographic Position Image\")\ntool_labels.append(\"Narrowness Index\")\ntool_labels.append(\"Natural Neighbour Interpolation\")\ntool_labels.append(\"Nearest Neighbour Gridding\")\ntool_labels.append(\"Negate\")\ntool_labels.append(\"New Raster From Base\")\ntool_labels.append(\"Normal Vectors\")\ntool_labels.append(\"Normalize Lidar\")\ntool_labels.append(\"Normalized Difference Index\")\ntool_labels.append(\"Not\")\ntool_labels.append(\"Not Equal To\")\ntool_labels.append(\"Num Downslope Neighbours\")\ntool_labels.append(\"Num Inflowing Neighbours\")\ntool_labels.append(\"Num Upslope Neighbours\")\ntool_labels.append(\"Olympic Filter\")\ntool_labels.append(\"Opening\")\ntool_labels.append(\"Openness\")\ntool_labels.append(\"Or\")\ntool_labels.append(\"Paired Sample T Test\")\ntool_labels.append(\"Panchromatic Sharpening\")\ntool_labels.append(\"Parallelepiped Classification\")\ntool_labels.append(\"Patch Orientation\")\ntool_labels.append(\"Pennock Landform Class\")\ntool_labels.append(\"Percent Elev Range\")\ntool_labels.append(\"Percent Equal To\")\ntool_labels.append(\"Percent Greater Than\")\ntool_labels.append(\"Percent Less Than\")\ntool_labels.append(\"Percentage Contrast Stretch\")\ntool_labels.append(\"Percentile Filter\")\ntool_labels.append(\"Perimeter Area Ratio\")\ntool_labels.append(\"Phi Coefficient\")\ntool_labels.append(\"Pick From List\")\ntool_labels.append(\"Piecewise Contrast Stretch\")\ntool_labels.append(\"Plan Curvature\")\ntool_labels.append(\"Polygon Area\")\ntool_labels.append(\"Polygon Long Axis\")\ntool_labels.append(\"Polygon Perimeter\")\ntool_labels.append(\"Polygon Short Axis\")\ntool_labels.append(\"Polygonize\")\ntool_labels.append(\"Polygons To Lines\")\ntool_labels.append(\"Power\")\ntool_labels.append(\"Prewitt Filter\")\ntool_labels.append(\"Principal Component Analysis\")\ntool_labels.append(\"Print Geo Tiff Tags\")\ntool_labels.append(\"Profile\")\ntool_labels.append(\"Profile Curvature\")\ntool_labels.append(\"Qin Flow Accumulation\")\ntool_labels.append(\"Quantiles\")\ntool_labels.append(\"Quinn Flow Accumulation\")\ntool_labels.append(\"Radial Basis Function Interpolation\")\ntool_labels.append(\"Radius Of Gyration\")\ntool_labels.append(\"Raise Walls\")\ntool_labels.append(\"Random Field\")\ntool_labels.append(\"Random Forest Classification\")\ntool_labels.append(\"Random Forest Regression\")\ntool_labels.append(\"Random Sample\")\ntool_labels.append(\"Range Filter\")\ntool_labels.append(\"Raster Area\")\ntool_labels.append(\"Raster Calculator\")\ntool_labels.append(\"Raster Cell Assignment\")\ntool_labels.append(\"Raster Histogram\")\ntool_labels.append(\"Raster Perimeter\")\ntool_labels.append(\"Raster Streams To Vector\")\ntool_labels.append(\"Raster Summary Stats\")\ntool_labels.append(\"Raster To Vector Lines\")\ntool_labels.append(\"Raster To Vector Points\")\ntool_labels.append(\"Raster To Vector Polygons\")\ntool_labels.append(\"Rasterize Streams\")\ntool_labels.append(\"Reciprocal\")\ntool_labels.append(\"Reclass\")\ntool_labels.append(\"Reclass Equal Interval\")\ntool_labels.append(\"Reclass From File\")\ntool_labels.append(\"Reconcile Multiple Headers\")\ntool_labels.append(\"Recover Flightline Info\")\ntool_labels.append(\"Recreate Pass Lines\")\ntool_labels.append(\"Reinitialize Attribute Table\")\ntool_labels.append(\"Related Circumscribing Circle\")\ntool_labels.append(\"Relative Aspect\")\ntool_labels.append(\"Relative Topographic Position\")\ntool_labels.append(\"Remove Field Edge Points\")\ntool_labels.append(\"Remove Off Terrain Objects\")\ntool_labels.append(\"Remove Polygon Holes\")\ntool_labels.append(\"Remove Raster Polygon Holes\")\ntool_labels.append(\"Remove Short Streams\")\ntool_labels.append(\"Remove Spurs\")\ntool_labels.append(\"Repair Stream Vector Topology\")\ntool_labels.append(\"Resample\")\ntool_labels.append(\"Rescale Value Range\")\ntool_labels.append(\"Rgb To Ihs\")\ntool_labels.append(\"Rho8 Flow Accumulation\")\ntool_labels.append(\"Rho8 Pointer\")\ntool_labels.append(\"Ring Curvature\")\ntool_labels.append(\"River Centerlines\")\ntool_labels.append(\"Roberts Cross Filter\")\ntool_labels.append(\"Root Mean Square Error\")\ntool_labels.append(\"Rotor\")\ntool_labels.append(\"Round\")\ntool_labels.append(\"Ruggedness Index\")\ntool_labels.append(\"Scharr Filter\")\ntool_labels.append(\"Sediment Transport Index\")\ntool_labels.append(\"Select Tiles By Polygon\")\ntool_labels.append(\"Set Nodata Value\")\ntool_labels.append(\"Shadow Animation\")\ntool_labels.append(\"Shadow Image\")\ntool_labels.append(\"Shape Complexity Index\")\ntool_labels.append(\"Shape Complexity Index Raster\")\ntool_labels.append(\"Shape Index\")\ntool_labels.append(\"Shreve Stream Magnitude\")\ntool_labels.append(\"Sigmoidal Contrast Stretch\")\ntool_labels.append(\"Sin\")\ntool_labels.append(\"Single Part To Multi Part\")\ntool_labels.append(\"Sinh\")\ntool_labels.append(\"Sink\")\ntool_labels.append(\"Slope\")\ntool_labels.append(\"Slope Vs Aspect Plot\")\ntool_labels.append(\"Slope Vs Elevation Plot\")\ntool_labels.append(\"Smooth Vectors\")\ntool_labels.append(\"Smooth Vegetation Residual\")\ntool_labels.append(\"Snap Pour Points\")\ntool_labels.append(\"Sobel Filter\")\ntool_labels.append(\"Sort Lidar\")\ntool_labels.append(\"Spherical Std Dev Of Normals\")\ntool_labels.append(\"Split Colour Composite\")\ntool_labels.append(\"Split Lidar\")\ntool_labels.append(\"Split Vector Lines\")\ntool_labels.append(\"Split With Lines\")\ntool_labels.append(\"Square\")\ntool_labels.append(\"Square Root\")\ntool_labels.append(\"Standard Deviation Contrast Stretch\")\ntool_labels.append(\"Standard Deviation Filter\")\ntool_labels.append(\"Standard Deviation Of Slope\")\ntool_labels.append(\"Stochastic Depression Analysis\")\ntool_labels.append(\"Strahler Order Basins\")\ntool_labels.append(\"Strahler Stream Order\")\ntool_labels.append(\"Stream Link Class\")\ntool_labels.append(\"Stream Link Identifier\")\ntool_labels.append(\"Stream Link Length\")\ntool_labels.append(\"Stream Link Slope\")\ntool_labels.append(\"Stream Power Index\")\ntool_labels.append(\"Stream Slope Continuous\")\ntool_labels.append(\"Subbasins\")\ntool_labels.append(\"Subtract\")\ntool_labels.append(\"Sum Overlay\")\ntool_labels.append(\"Surface Area Ratio\")\ntool_labels.append(\"Svm Classification\")\ntool_labels.append(\"Svm Regression\")\ntool_labels.append(\"Symmetrical Difference\")\ntool_labels.append(\"Tan\")\ntool_labels.append(\"Tangential Curvature\")\ntool_labels.append(\"Tanh\")\ntool_labels.append(\"Thicken Raster Line\")\ntool_labels.append(\"Time In Daylight\")\ntool_labels.append(\"Tin Gridding\")\ntool_labels.append(\"To Degrees\")\ntool_labels.append(\"To Radians\")\ntool_labels.append(\"Tophat Transform\")\ntool_labels.append(\"Topo Render\")\ntool_labels.append(\"Topographic Position Animation\")\ntool_labels.append(\"Topological Stream Order\")\ntool_labels.append(\"Total Curvature\")\ntool_labels.append(\"Total Filter\")\ntool_labels.append(\"Trace Downslope Flowpaths\")\ntool_labels.append(\"Travelling Salesman Problem\")\ntool_labels.append(\"Trend Surface\")\ntool_labels.append(\"Trend Surface Vector Points\")\ntool_labels.append(\"Tributary Identifier\")\ntool_labels.append(\"Truncate\")\ntool_labels.append(\"Turning Bands Simulation\")\ntool_labels.append(\"Two Sample Ks Test\")\ntool_labels.append(\"Union\")\ntool_labels.append(\"Unnest Basins\")\ntool_labels.append(\"Unsharp Masking\")\ntool_labels.append(\"Unsphericity\")\ntool_labels.append(\"Update Nodata Cells\")\ntool_labels.append(\"Upslope Depression Storage\")\ntool_labels.append(\"User Defined Weights Filter\")\ntool_labels.append(\"Vector Hex Binning\")\ntool_labels.append(\"Vector Lines To Raster\")\ntool_labels.append(\"Vector Points To Raster\")\ntool_labels.append(\"Vector Polygons To Raster\")\ntool_labels.append(\"Vector Stream Network Analysis\")\ntool_labels.append(\"Vertical Excess Curvature\")\ntool_labels.append(\"Viewshed\")\ntool_labels.append(\"Visibility Index\")\ntool_labels.append(\"Voronoi Diagram\")\ntool_labels.append(\"Watershed\")\ntool_labels.append(\"Weighted Overlay\")\ntool_labels.append(\"Weighted Sum\")\ntool_labels.append(\"Wetness Index\")\ntool_labels.append(\"Wilcoxon Signed Rank Test\")\ntool_labels.append(\"Write Function Memory Insertion\")\ntool_labels.append(\"Xor\")\ntool_labels.append(\"Yield Filter\")\ntool_labels.append(\"Yield Map\")\ntool_labels.append(\"Yield Normalization\")\ntool_labels.append(\"Z Scores\")\ntool_labels.append(\"Zlidar To Las\")\ntool_labels.append(\"Zonal Statistics\")\n\n\nclass Toolbox(object):\n    def __init__(self):\n        \"\"\"Define the toolbox (the name of the toolbox is the name of the .pyt file).\"\"\"\n        self.label = \"WhiteboxTools Toolbox\"\n        self.alias = \"WBT\"\n\n        # List of tool classes associated with this toolbox\n        tools = []        \n        tools.append(Help)\n        tools.append(License)\n        tools.append(Version)\n        tools.append(ListTools)\n        tools.append(ToolHelp)\n        tools.append(ToolParameters)\n        tools.append(ViewCode)\n        tools.append(RunTool)\n\n        tools.append(AbsoluteValue)\n        tools.append(AccumulationCurvature)\n        tools.append(AdaptiveFilter)\n        tools.append(Add)\n        tools.append(AddPointCoordinatesToTable)\n        tools.append(AggregateRaster)\n        tools.append(And)\n        tools.append(Anova)\n        tools.append(ArcCos)\n        tools.append(ArcSin)\n        tools.append(ArcTan)\n        tools.append(Arcosh)\n        tools.append(Arsinh)\n        tools.append(Artanh)\n        tools.append(AsciiToLas)\n        tools.append(Aspect)\n        tools.append(AssessRoute)\n        tools.append(Atan2)\n        tools.append(AttributeCorrelation)\n        tools.append(AttributeCorrelationNeighbourhoodAnalysis)\n        tools.append(AttributeHistogram)\n        tools.append(AttributeScattergram)\n        tools.append(AverageFlowpathSlope)\n        tools.append(AverageNormalVectorAngularDeviation)\n        tools.append(AverageOverlay)\n        tools.append(AverageUpslopeFlowpathLength)\n        tools.append(BalanceContrastEnhancement)\n        tools.append(Basins)\n        tools.append(BilateralFilter)\n        tools.append(BlockMaximumGridding)\n        tools.append(BlockMinimumGridding)\n        tools.append(BoundaryShapeComplexity)\n        tools.append(BreachDepressions)\n        tools.append(BreachDepressionsLeastCost)\n        tools.append(BreachSingleCellPits)\n        tools.append(BreaklineMapping)\n        tools.append(BufferRaster)\n        tools.append(BurnStreamsAtRoads)\n        tools.append(CannyEdgeDetection)\n        tools.append(Ceil)\n        tools.append(Centroid)\n        tools.append(CentroidVector)\n        tools.append(ChangeVectorAnalysis)\n        tools.append(CircularVarianceOfAspect)\n        tools.append(ClassifyBuildingsInLidar)\n        tools.append(ClassifyLidar)\n        tools.append(ClassifyOverlapPoints)\n        tools.append(CleanVector)\n        tools.append(Clip)\n        tools.append(ClipLidarToPolygon)\n        tools.append(ClipRasterToPolygon)\n        tools.append(Closing)\n        tools.append(Clump)\n        tools.append(ColourizeBasedOnClass)\n        tools.append(ColourizeBasedOnPointReturns)\n        tools.append(CompactnessRatio)\n        tools.append(ConditionalEvaluation)\n        tools.append(ConditionedLatinHypercube)\n        tools.append(ConservativeSmoothingFilter)\n        tools.append(ConstructVectorTin)\n        tools.append(ContoursFromPoints)\n        tools.append(ContoursFromRaster)\n        tools.append(ConvertNodataToZero)\n        tools.append(ConvertRasterFormat)\n        tools.append(CornerDetection)\n        tools.append(CorrectVignetting)\n        tools.append(Cos)\n        tools.append(Cosh)\n        tools.append(CostAllocation)\n        tools.append(CostDistance)\n        tools.append(CostPathway)\n        tools.append(CountIf)\n        tools.append(CreateColourComposite)\n        tools.append(CreateHexagonalVectorGrid)\n        tools.append(CreatePlane)\n        tools.append(CreateRectangularVectorGrid)\n        tools.append(CrispnessIndex)\n        tools.append(CrossTabulation)\n        tools.append(CsvPointsToVector)\n        tools.append(CumulativeDistribution)\n        tools.append(Curvedness)\n        tools.append(D8FlowAccumulation)\n        tools.append(D8MassFlux)\n        tools.append(D8Pointer)\n        tools.append(DInfFlowAccumulation)\n        tools.append(DInfMassFlux)\n        tools.append(DInfPointer)\n        tools.append(Dbscan)\n        tools.append(Decrement)\n        tools.append(DemVoidFilling)\n        tools.append(DepthInSink)\n        tools.append(DepthToWater)\n        tools.append(DevFromMeanElev)\n        tools.append(DiffFromMeanElev)\n        tools.append(DiffOfGaussianFilter)\n        tools.append(Difference)\n        tools.append(DifferenceCurvature)\n        tools.append(DirectDecorrelationStretch)\n        tools.append(DirectionalRelief)\n        tools.append(Dissolve)\n        tools.append(DistanceToOutlet)\n        tools.append(DiversityFilter)\n        tools.append(Divide)\n        tools.append(DownslopeDistanceToStream)\n        tools.append(DownslopeFlowpathLength)\n        tools.append(DownslopeIndex)\n        tools.append(EdgeContamination)\n        tools.append(EdgeDensity)\n        tools.append(EdgePreservingMeanFilter)\n        tools.append(EdgeProportion)\n        tools.append(ElevAbovePit)\n        tools.append(ElevPercentile)\n        tools.append(ElevRelativeToMinMax)\n        tools.append(ElevRelativeToWatershedMinMax)\n        tools.append(ElevationAboveStream)\n        tools.append(ElevationAboveStreamEuclidean)\n        tools.append(EliminateCoincidentPoints)\n        tools.append(ElongationRatio)\n        tools.append(EmbankmentMapping)\n        tools.append(EmbossFilter)\n        tools.append(EqualTo)\n        tools.append(Erase)\n        tools.append(ErasePolygonFromLidar)\n        tools.append(ErasePolygonFromRaster)\n        tools.append(EuclideanAllocation)\n        tools.append(EuclideanDistance)\n        tools.append(EvaluateTrainingSites)\n        tools.append(Exp)\n        tools.append(Exp2)\n        tools.append(ExportTableToCsv)\n        tools.append(ExposureTowardsWindFlux)\n        tools.append(ExtendVectorLines)\n        tools.append(ExtractNodes)\n        tools.append(ExtractRasterValuesAtPoints)\n        tools.append(ExtractStreams)\n        tools.append(ExtractValleys)\n        tools.append(Fd8FlowAccumulation)\n        tools.append(Fd8Pointer)\n        tools.append(FarthestChannelHead)\n        tools.append(FastAlmostGaussianFilter)\n        tools.append(FeaturePreservingSmoothing)\n        tools.append(FetchAnalysis)\n        tools.append(FillBurn)\n        tools.append(FillDepressions)\n        tools.append(FillDepressionsPlanchonAndDarboux)\n        tools.append(FillDepressionsWangAndLiu)\n        tools.append(FillMissingData)\n        tools.append(FillSingleCellPits)\n        tools.append(FilterLidar)\n        tools.append(FilterLidarClasses)\n        tools.append(FilterLidarScanAngles)\n        tools.append(FilterRasterFeaturesByArea)\n        tools.append(FindFlightlineEdgePoints)\n        tools.append(FindLowestOrHighestPoints)\n        tools.append(FindMainStem)\n        tools.append(FindNoFlowCells)\n        tools.append(FindParallelFlow)\n        tools.append(FindPatchOrClassEdgeCells)\n        tools.append(FindRidges)\n        tools.append(FixDanglingArcs)\n        tools.append(FlattenLakes)\n        tools.append(FlightlineOverlap)\n        tools.append(FlipImage)\n        tools.append(FloodOrder)\n        tools.append(Floor)\n        tools.append(FlowAccumulationFullWorkflow)\n        tools.append(FlowLengthDiff)\n        tools.append(GammaCorrection)\n        tools.append(GaussianContrastStretch)\n        tools.append(GaussianCurvature)\n        tools.append(GaussianFilter)\n        tools.append(GaussianScaleSpace)\n        tools.append(GeneralizeClassifiedRaster)\n        tools.append(GeneralizeWithSimilarity)\n        tools.append(GeneratingFunction)\n        tools.append(Geomorphons)\n        tools.append(GreaterThan)\n        tools.append(HackStreamOrder)\n        tools.append(HeatMap)\n        tools.append(HeightAboveGround)\n        tools.append(HighPassBilateralFilter)\n        tools.append(HighPassFilter)\n        tools.append(HighPassMedianFilter)\n        tools.append(HighestPosition)\n        tools.append(Hillshade)\n        tools.append(Hillslopes)\n        tools.append(HistogramEqualization)\n        tools.append(HistogramMatching)\n        tools.append(HistogramMatchingTwoImages)\n        tools.append(HoleProportion)\n        tools.append(HorizonAngle)\n        tools.append(HorizontalExcessCurvature)\n        tools.append(HortonStreamOrder)\n        tools.append(HydrologicConnectivity)\n        tools.append(HypsometricAnalysis)\n        tools.append(HypsometricallyTintedHillshade)\n        tools.append(IdwInterpolation)\n        tools.append(IhsToRgb)\n        tools.append(ImageAutocorrelation)\n        tools.append(ImageCorrelation)\n        tools.append(ImageCorrelationNeighbourhoodAnalysis)\n        tools.append(ImageRegression)\n        tools.append(ImageSegmentation)\n        tools.append(ImageSlider)\n        tools.append(ImageStackProfile)\n        tools.append(ImpoundmentSizeIndex)\n        tools.append(InPlaceAdd)\n        tools.append(InPlaceDivide)\n        tools.append(InPlaceMultiply)\n        tools.append(InPlaceSubtract)\n        tools.append(Increment)\n        tools.append(IndividualTreeDetection)\n        tools.append(InsertDams)\n        tools.append(InstallWbExtension)\n        tools.append(IntegerDivision)\n        tools.append(IntegralImage)\n        tools.append(Intersect)\n        tools.append(InversePrincipalComponentAnalysis)\n        tools.append(IsNoData)\n        tools.append(Isobasins)\n        tools.append(JensonSnapPourPoints)\n        tools.append(JoinTables)\n        tools.append(KMeansClustering)\n        tools.append(KNearestMeanFilter)\n        tools.append(KappaIndex)\n        tools.append(KnnClassification)\n        tools.append(KnnRegression)\n        tools.append(KsTestForNormality)\n        tools.append(LaplacianFilter)\n        tools.append(LaplacianOfGaussianFilter)\n        tools.append(LasToAscii)\n        tools.append(LasToLaz)\n        tools.append(LasToMultipointShapefile)\n        tools.append(LasToShapefile)\n        tools.append(LasToZlidar)\n        tools.append(LaunchWbRunner)\n        tools.append(LayerFootprint)\n        tools.append(LazToLas)\n        tools.append(LeeSigmaFilter)\n        tools.append(LengthOfUpstreamChannels)\n        tools.append(LessThan)\n        tools.append(LidarBlockMaximum)\n        tools.append(LidarBlockMinimum)\n        tools.append(LidarClassifySubset)\n        tools.append(LidarColourize)\n        tools.append(LidarContour)\n        tools.append(LidarDigitalSurfaceModel)\n        tools.append(LidarEigenvalueFeatures)\n        tools.append(LidarElevationSlice)\n        tools.append(LidarGroundPointFilter)\n        tools.append(LidarHexBinning)\n        tools.append(LidarHillshade)\n        tools.append(LidarHistogram)\n        tools.append(LidarIdwInterpolation)\n        tools.append(LidarInfo)\n        tools.append(LidarJoin)\n        tools.append(LidarKappaIndex)\n        tools.append(LidarNearestNeighbourGridding)\n        tools.append(LidarPointDensity)\n        tools.append(LidarPointReturnAnalysis)\n        tools.append(LidarPointStats)\n        tools.append(LidarRansacPlanes)\n        tools.append(LidarRbfInterpolation)\n        tools.append(LidarRemoveDuplicates)\n        tools.append(LidarRemoveOutliers)\n        tools.append(LidarRooftopAnalysis)\n        tools.append(LidarSegmentation)\n        tools.append(LidarSegmentationBasedFilter)\n        tools.append(LidarShift)\n        tools.append(LidarSibsonInterpolation)\n        tools.append(LidarTinGridding)\n        tools.append(LidarThin)\n        tools.append(LidarThinHighDensity)\n        tools.append(LidarTile)\n        tools.append(LidarTileFootprint)\n        tools.append(LidarTophatTransform)\n        tools.append(LineDetectionFilter)\n        tools.append(LineIntersections)\n        tools.append(LineThinning)\n        tools.append(LinearityIndex)\n        tools.append(LinesToPolygons)\n        tools.append(ListUniqueValues)\n        tools.append(ListUniqueValuesRaster)\n        tools.append(Ln)\n        tools.append(LocalHypsometricAnalysis)\n        tools.append(LocalQuadraticRegression)\n        tools.append(Log10)\n        tools.append(Log2)\n        tools.append(LogisticRegression)\n        tools.append(LongProfile)\n        tools.append(LongProfileFromPoints)\n        tools.append(LongestFlowpath)\n        tools.append(LowPointsOnHeadwaterDivides)\n        tools.append(LowestPosition)\n        tools.append(MdInfFlowAccumulation)\n        tools.append(MajorityFilter)\n        tools.append(MapOffTerrainObjects)\n        tools.append(Max)\n        tools.append(MaxAbsoluteOverlay)\n        tools.append(MaxAnisotropyDev)\n        tools.append(MaxAnisotropyDevSignature)\n        tools.append(MaxBranchLength)\n        tools.append(MaxDifferenceFromMean)\n        tools.append(MaxDownslopeElevChange)\n        tools.append(MaxElevDevSignature)\n        tools.append(MaxElevationDeviation)\n        tools.append(MaxOverlay)\n        tools.append(MaxUpslopeElevChange)\n        tools.append(MaxUpslopeFlowpathLength)\n        tools.append(MaxUpslopeValue)\n        tools.append(MaximalCurvature)\n        tools.append(MaximumFilter)\n        tools.append(MeanCurvature)\n        tools.append(MeanFilter)\n        tools.append(MedianFilter)\n        tools.append(Medoid)\n        tools.append(MergeLineSegments)\n        tools.append(MergeTableWithCsv)\n        tools.append(MergeVectors)\n        tools.append(Min)\n        tools.append(MinAbsoluteOverlay)\n        tools.append(MinDistClassification)\n        tools.append(MinDownslopeElevChange)\n        tools.append(MinMaxContrastStretch)\n        tools.append(MinOverlay)\n        tools.append(MinimalCurvature)\n        tools.append(MinimumBoundingBox)\n        tools.append(MinimumBoundingCircle)\n        tools.append(MinimumBoundingEnvelope)\n        tools.append(MinimumConvexHull)\n        tools.append(MinimumFilter)\n        tools.append(ModifiedKMeansClustering)\n        tools.append(ModifyLidar)\n        tools.append(ModifyNoDataValue)\n        tools.append(Modulo)\n        tools.append(Mosaic)\n        tools.append(MosaicWithFeathering)\n        tools.append(MultiPartToSinglePart)\n        tools.append(MultidirectionalHillshade)\n        tools.append(Multiply)\n        tools.append(MultiplyOverlay)\n        tools.append(MultiscaleCurvatures)\n        tools.append(MultiscaleElevationPercentile)\n        tools.append(MultiscaleRoughness)\n        tools.append(MultiscaleRoughnessSignature)\n        tools.append(MultiscaleStdDevNormals)\n        tools.append(MultiscaleStdDevNormalsSignature)\n        tools.append(MultiscaleTopographicPositionImage)\n        tools.append(NarrownessIndex)\n        tools.append(NaturalNeighbourInterpolation)\n        tools.append(NearestNeighbourGridding)\n        tools.append(Negate)\n        tools.append(NewRasterFromBase)\n        tools.append(NormalVectors)\n        tools.append(NormalizeLidar)\n        tools.append(NormalizedDifferenceIndex)\n        tools.append(Not)\n        tools.append(NotEqualTo)\n        tools.append(NumDownslopeNeighbours)\n        tools.append(NumInflowingNeighbours)\n        tools.append(NumUpslopeNeighbours)\n        tools.append(OlympicFilter)\n        tools.append(Opening)\n        tools.append(Openness)\n        tools.append(Or)\n        tools.append(PairedSampleTTest)\n        tools.append(PanchromaticSharpening)\n        tools.append(ParallelepipedClassification)\n        tools.append(PatchOrientation)\n        tools.append(PennockLandformClass)\n        tools.append(PercentElevRange)\n        tools.append(PercentEqualTo)\n        tools.append(PercentGreaterThan)\n        tools.append(PercentLessThan)\n        tools.append(PercentageContrastStretch)\n        tools.append(PercentileFilter)\n        tools.append(PerimeterAreaRatio)\n        tools.append(PhiCoefficient)\n        tools.append(PickFromList)\n        tools.append(PiecewiseContrastStretch)\n        tools.append(PlanCurvature)\n        tools.append(PolygonArea)\n        tools.append(PolygonLongAxis)\n        tools.append(PolygonPerimeter)\n        tools.append(PolygonShortAxis)\n        tools.append(Polygonize)\n        tools.append(PolygonsToLines)\n        tools.append(Power)\n        tools.append(PrewittFilter)\n        tools.append(PrincipalComponentAnalysis)\n        tools.append(PrintGeoTiffTags)\n        tools.append(Profile)\n        tools.append(ProfileCurvature)\n        tools.append(QinFlowAccumulation)\n        tools.append(Quantiles)\n        tools.append(QuinnFlowAccumulation)\n        tools.append(RadialBasisFunctionInterpolation)\n        tools.append(RadiusOfGyration)\n        tools.append(RaiseWalls)\n        tools.append(RandomField)\n        tools.append(RandomForestClassification)\n        tools.append(RandomForestRegression)\n        tools.append(RandomSample)\n        tools.append(RangeFilter)\n        tools.append(RasterArea)\n        tools.append(RasterCalculator)\n        tools.append(RasterCellAssignment)\n        tools.append(RasterHistogram)\n        tools.append(RasterPerimeter)\n        tools.append(RasterStreamsToVector)\n        tools.append(RasterSummaryStats)\n        tools.append(RasterToVectorLines)\n        tools.append(RasterToVectorPoints)\n        tools.append(RasterToVectorPolygons)\n        tools.append(RasterizeStreams)\n        tools.append(Reciprocal)\n        tools.append(Reclass)\n        tools.append(ReclassEqualInterval)\n        tools.append(ReclassFromFile)\n        tools.append(ReconcileMultipleHeaders)\n        tools.append(RecoverFlightlineInfo)\n        tools.append(RecreatePassLines)\n        tools.append(ReinitializeAttributeTable)\n        tools.append(RelatedCircumscribingCircle)\n        tools.append(RelativeAspect)\n        tools.append(RelativeTopographicPosition)\n        tools.append(RemoveFieldEdgePoints)\n        tools.append(RemoveOffTerrainObjects)\n        tools.append(RemovePolygonHoles)\n        tools.append(RemoveRasterPolygonHoles)\n        tools.append(RemoveShortStreams)\n        tools.append(RemoveSpurs)\n        tools.append(RepairStreamVectorTopology)\n        tools.append(Resample)\n        tools.append(RescaleValueRange)\n        tools.append(RgbToIhs)\n        tools.append(Rho8FlowAccumulation)\n        tools.append(Rho8Pointer)\n        tools.append(RingCurvature)\n        tools.append(RiverCenterlines)\n        tools.append(RobertsCrossFilter)\n        tools.append(RootMeanSquareError)\n        tools.append(Rotor)\n        tools.append(Round)\n        tools.append(RuggednessIndex)\n        tools.append(ScharrFilter)\n        tools.append(SedimentTransportIndex)\n        tools.append(SelectTilesByPolygon)\n        tools.append(SetNodataValue)\n        tools.append(ShadowAnimation)\n        tools.append(ShadowImage)\n        tools.append(ShapeComplexityIndex)\n        tools.append(ShapeComplexityIndexRaster)\n        tools.append(ShapeIndex)\n        tools.append(ShreveStreamMagnitude)\n        tools.append(SigmoidalContrastStretch)\n        tools.append(Sin)\n        tools.append(SinglePartToMultiPart)\n        tools.append(Sinh)\n        tools.append(Sink)\n        tools.append(Slope)\n        tools.append(SlopeVsAspectPlot)\n        tools.append(SlopeVsElevationPlot)\n        tools.append(SmoothVectors)\n        tools.append(SmoothVegetationResidual)\n        tools.append(SnapPourPoints)\n        tools.append(SobelFilter)\n        tools.append(SortLidar)\n        tools.append(SphericalStdDevOfNormals)\n        tools.append(SplitColourComposite)\n        tools.append(SplitLidar)\n        tools.append(SplitVectorLines)\n        tools.append(SplitWithLines)\n        tools.append(Square)\n        tools.append(SquareRoot)\n        tools.append(StandardDeviationContrastStretch)\n        tools.append(StandardDeviationFilter)\n        tools.append(StandardDeviationOfSlope)\n        tools.append(StochasticDepressionAnalysis)\n        tools.append(StrahlerOrderBasins)\n        tools.append(StrahlerStreamOrder)\n        tools.append(StreamLinkClass)\n        tools.append(StreamLinkIdentifier)\n        tools.append(StreamLinkLength)\n        tools.append(StreamLinkSlope)\n        tools.append(StreamPowerIndex)\n        tools.append(StreamSlopeContinuous)\n        tools.append(Subbasins)\n        tools.append(Subtract)\n        tools.append(SumOverlay)\n        tools.append(SurfaceAreaRatio)\n        tools.append(SvmClassification)\n        tools.append(SvmRegression)\n        tools.append(SymmetricalDifference)\n        tools.append(TinGridding)\n        tools.append(Tan)\n        tools.append(TangentialCurvature)\n        tools.append(Tanh)\n        tools.append(ThickenRasterLine)\n        tools.append(TimeInDaylight)\n        tools.append(ToDegrees)\n        tools.append(ToRadians)\n        tools.append(TophatTransform)\n        tools.append(TopoRender)\n        tools.append(TopographicPositionAnimation)\n        tools.append(TopologicalStreamOrder)\n        tools.append(TotalCurvature)\n        tools.append(TotalFilter)\n        tools.append(TraceDownslopeFlowpaths)\n        tools.append(TravellingSalesmanProblem)\n        tools.append(TrendSurface)\n        tools.append(TrendSurfaceVectorPoints)\n        tools.append(TributaryIdentifier)\n        tools.append(Truncate)\n        tools.append(TurningBandsSimulation)\n        tools.append(TwoSampleKsTest)\n        tools.append(Union)\n        tools.append(UnnestBasins)\n        tools.append(UnsharpMasking)\n        tools.append(Unsphericity)\n        tools.append(UpdateNodataCells)\n        tools.append(UpslopeDepressionStorage)\n        tools.append(UserDefinedWeightsFilter)\n        tools.append(VectorHexBinning)\n        tools.append(VectorLinesToRaster)\n        tools.append(VectorPointsToRaster)\n        tools.append(VectorPolygonsToRaster)\n        tools.append(VectorStreamNetworkAnalysis)\n        tools.append(VerticalExcessCurvature)\n        tools.append(Viewshed)\n        tools.append(VisibilityIndex)\n        tools.append(VoronoiDiagram)\n        tools.append(Watershed)\n        tools.append(WeightedOverlay)\n        tools.append(WeightedSum)\n        tools.append(WetnessIndex)\n        tools.append(WilcoxonSignedRankTest)\n        tools.append(WriteFunctionMemoryInsertion)\n        tools.append(Xor)\n        tools.append(YieldFilter)\n        tools.append(YieldMap)\n        tools.append(YieldNormalization)\n        tools.append(ZScores)\n        tools.append(ZlidarToLas)\n        tools.append(ZonalStatistics)\n\n        self.tools = tools\n\n\nclass Help(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"Help\"\n        self.description = \"Help description for WhiteboxTools\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        params = None\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        messages.addMessage(wbt.help())\n        return\n\n\nclass License(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"License\"\n        self.description = \"License information for WhiteboxTools.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        params = None\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        messages.addMessage(wbt.license())\n        return\n\n\nclass Version(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"Version\"\n        self.description = \"Version information for WhiteboxTools.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        params = None\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        messages.addMessage(wbt.version())\n        return\n\n\nclass ListTools(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"List Tools\"\n        self.description = \"All available tools in WhiteboxTools.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n\n        # First parameter\n        param0 = arcpy.Parameter(\n            displayName=\"Keywords\",\n            name=\"keywords\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        # param0.multiValue = True\n        param0.value = \"lidar\"\n        params = [param0]\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        param0 = parameters[0].valueAsText\n\n        if param0 is None:\n            tools = wbt.list_tools()\n        else:\n            tools = wbt.list_tools([param0])\n            \n        for index, tool in enumerate(sorted(tools)):\n            messages.addMessage(\"{}. {}: {}\".format(index + 1, tool, tools[tool]))\n        return\n\n\nclass ToolHelp(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"Tool Help\"\n        self.description = \"Help description for a specific tool.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        tool_name = arcpy.Parameter(\n            displayName=\"Select a tool\",\n            name=\"tool_name\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        tool_name.value = \"Lidar Info\"\n        tool_name.filter.type = \"ValueList\"\n        tool_name.filter.list = tool_labels\n\n        params = [tool_name]\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        param0 = parameters[0].valueAsText\n        tool_name = param0.replace(\" \", \"\").strip()\n        messages.addMessage(wbt.tool_help(tool_name))\n        return\n\n\nclass ToolParameters(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"Tool Parameters\"\n        self.description = \"Tool parameter descriptions for a specific tool.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        tool_name = arcpy.Parameter(\n            displayName=\"Select a tool\",\n            name=\"tool_name\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        tool_name.value = \"Lidar Info\"\n        tool_name.filter.type = \"ValueList\"\n        tool_name.filter.list = tool_labels\n\n        params = [tool_name]\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        param0 = parameters[0].valueAsText\n        tool_name = param0.replace(\" \", \"\").strip()\n        messages.addMessage(wbt.tool_parameters(tool_name))\n        return\n\n\nclass ViewCode(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"View Code\"\n        self.description = \"Source code for a specific tool.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        tool_name = arcpy.Parameter(\n            displayName=\"Select a tool\",\n            name=\"tool_name\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        tool_name.value = \"Lidar Info\"\n        tool_name.filter.type = \"ValueList\"\n        tool_name.filter.list = tool_labels\n\n        params = [tool_name]\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        param0 = parameters[0].valueAsText\n        tool_name = param0.replace(\" \", \"\").strip()        \n        messages.addMessage(\"Opening default browser...\")\n        webbrowser.get('windows-default').open(wbt.view_code(tool_name))\n        messages.addMessage(wbt.view_code(tool_name))\n        return\n\n\nclass RunTool(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"Run Tool\"\n        self.description = \"Runs a tool and specifies tool arguments.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        tool_name = arcpy.Parameter(\n            displayName=\"Select a tool\",\n            name=\"tool_name\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        tool_name.value = \"Breach Depressions\"\n        tool_name.filter.type = \"ValueList\"\n        tool_name.filter.list = tool_labels\n\n        args = arcpy.Parameter(\n            displayName=\"Arguments\",\n            name=\"agrs\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        args.value = '--dem=\"/path/to/DEM.tif\"  --output=\"/path/to/output.tif\"'\n\n        params = [tool_name, args]\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        param0 = parameters[0].valueAsText\n        args = parameters[1].valueAsText\n        tool_name = param0.replace(\" \", \"\").strip()\n        dir_path = os.path.dirname(os.path.realpath(__file__))    \n        exe_path = os.path.join(dir_path, \"WBT/whitebox_tools.exe\")\n        cmd = '{} --run={} {}'.format(exe_path, tool_name, args)\n        if \"-v\" not in cmd:\n            cmd = cmd + ' -v'  \n        messages.addMessage(cmd)  \n        messages.addMessage(os.popen(cmd).read().rstrip())\n        return\n\n\nclass AbsoluteValue(object):\n    def __init__(self):\n        self.label = \"Absolute Value\"\n        self.description = \"Calculates the absolute value of every cell in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.absolute_value(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AccumulationCurvature(object):\n    def __init__(self):\n        self.label = \"Accumulation Curvature\"\n        self.description = \"This tool calculates accumulation curvature from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.accumulation_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AdaptiveFilter(object):\n    def __init__(self):\n        self.label = \"Adaptive Filter\"\n        self.description = \"Performs an adaptive filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Difference From Mean Threshold (# Std. Dev.)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        threshold.value = '2.0'\n\n        params = [i, output, filterx, filtery, threshold]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        threshold = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.adaptive_filter(i=i, output=output, filterx=filterx, filtery=filtery, threshold=threshold)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Add(object):\n    def __init__(self):\n        self.label = \"Add\"\n        self.description = \"Performs an addition operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.add(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AddPointCoordinatesToTable(object):\n    def __init__(self):\n        self.label = \"Add Point Coordinates To Table\"\n        self.description = \"Modifies the attribute table of a point vector by adding fields containing each point's X and Y coordinates.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.add_point_coordinates_to_table(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AggregateRaster(object):\n    def __init__(self):\n        self.label = \"Aggregate Raster\"\n        self.description = \"Aggregates a raster to a lower resolution.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        agg_factor = arcpy.Parameter(\n            displayName=\"Aggregation Factor (pixels)\",\n            name=\"agg_factor\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        agg_factor.value = '2'\n\n        type = arcpy.Parameter(\n            displayName=\"Aggregation Type\",\n            name=\"type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        type.filter.type = \"ValueList\"\n        type.filter.list = ['mean', 'sum', 'maximum', 'minimum', 'range']\n        type.value = 'mean'\n\n        params = [i, output, agg_factor, type]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        agg_factor = parameters[2].valueAsText\n        type = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.aggregate_raster(i=i, output=output, agg_factor=agg_factor, type=type)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass And(object):\n    def __init__(self):\n        self.label = \"And\"\n        self.description = \"Performs a logical AND operator on two Boolean raster images.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.And(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Anova(object):\n    def __init__(self):\n        self.label = \"Anova\"\n        self.description = \"Performs an analysis of variance (ANOVA) test on a raster dataset.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        features = arcpy.Parameter(\n            displayName=\"Feature Definition (Class) File\",\n            name=\"features\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [i, features, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        features = parameters[1].valueAsText\n        if features is not None:\n            desc = arcpy.Describe(features)\n            features = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.anova(i=i, features=features, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ArcCos(object):\n    def __init__(self):\n        self.label = \"Arc Cos\"\n        self.description = \"Returns the inverse cosine (arccos) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.arc_cos(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ArcSin(object):\n    def __init__(self):\n        self.label = \"Arc Sin\"\n        self.description = \"Returns the inverse sine (arcsin) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.arc_sin(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ArcTan(object):\n    def __init__(self):\n        self.label = \"Arc Tan\"\n        self.description = \"Returns the inverse tangent (arctan) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.arc_tan(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Arcosh(object):\n    def __init__(self):\n        self.label = \"Arcosh\"\n        self.description = \"Returns the inverse hyperbolic cosine (arcosh) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.arcosh(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Arsinh(object):\n    def __init__(self):\n        self.label = \"Arsinh\"\n        self.description = \"Returns the inverse hyperbolic sine (arsinh) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.arsinh(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Artanh(object):\n    def __init__(self):\n        self.label = \"Artanh\"\n        self.description = \"Returns the inverse hyperbolic tangent (arctanh) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.artanh(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AsciiToLas(object):\n    def __init__(self):\n        self.label = \"Ascii To Las\"\n        self.description = \"Converts one or more ASCII files containing LiDAR points into LAS files.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input LiDAR point ASCII Files (.csv)\",\n            name=\"inputs\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n        inputs.filter.list = [\"csv\"]\n\n        pattern = arcpy.Parameter(\n            displayName=\"Pattern\",\n            name=\"pattern\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        proj = arcpy.Parameter(\n            displayName=\"Well-known-text (WKT) string or EPSG code\",\n            name=\"proj\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [inputs, pattern, proj]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        pattern = parameters[1].valueAsText\n        proj = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.ascii_to_las(inputs=inputs, pattern=pattern, proj=proj)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Aspect(object):\n    def __init__(self):\n        self.label = \"Aspect\"\n        self.description = \"Calculates an aspect raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        zfactor = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.aspect(dem=dem, output=output, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AssessRoute(object):\n    def __init__(self):\n        self.label = \"Assess Route\"\n        self.description = \"This tool assesses a route for slope, elevation, and visibility variation.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        routes = arcpy.Parameter(\n            displayName=\"Input Routes Vector\",\n            name=\"routes\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        routes.filter.list = [\"Polyline\"]\n\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Lines\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        length = arcpy.Parameter(\n            displayName=\"Max Segment Length\",\n            name=\"length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        dist = arcpy.Parameter(\n            displayName=\"Search Distance (grid cells)\",\n            name=\"dist\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        dist.value = '20'\n\n        params = [routes, dem, output, length, dist]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        routes = parameters[0].valueAsText\n        if routes is not None:\n            desc = arcpy.Describe(routes)\n            routes = desc.catalogPath\n        dem = parameters[1].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[2].valueAsText\n        length = parameters[3].valueAsText\n        dist = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.assess_route(routes=routes, dem=dem, output=output, length=length, dist=dist)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Atan2(object):\n    def __init__(self):\n        self.label = \"Atan2\"\n        self.description = \"Returns the 2-argument inverse tangent (atan2).\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input_y = arcpy.Parameter(\n            displayName=\"Input Y File Or Constant Value\",\n            name=\"input_y\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input_x = arcpy.Parameter(\n            displayName=\"Input X File Or Constant Value\",\n            name=\"input_x\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input_y, input_x, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input_y = parameters[0].valueAsText\n        if input_y is not None:\n            try:\n                input_y = str(float(input_y))\n            except:\n                desc = arcpy.Describe(input_y)\n                input_y = desc.catalogPath\n        input_x = parameters[1].valueAsText\n        if input_x is not None:\n            try:\n                input_x = str(float(input_x))\n            except:\n                desc = arcpy.Describe(input_x)\n                input_x = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.atan2(input_y=input_y, input_x=input_x, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AttributeCorrelation(object):\n    def __init__(self):\n        self.label = \"Attribute Correlation\"\n        self.description = \"Performs a correlation analysis on attribute fields from a vector database.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.attribute_correlation(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AttributeCorrelationNeighbourhoodAnalysis(object):\n    def __init__(self):\n        self.label = \"Attribute Correlation Neighbourhood Analysis\"\n        self.description = \"Performs a correlation on two input vector attributes within a neighbourhood search windows.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        field1 = arcpy.Parameter(\n            displayName=\"Field Name 1\",\n            name=\"field1\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field1.parameterDependencies = [i.name]\n\n        field2 = arcpy.Parameter(\n            displayName=\"Field Name 2\",\n            name=\"field2\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field2.parameterDependencies = [i.name]\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius (map units)\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        min_points = arcpy.Parameter(\n            displayName=\"Min. Number of Points\",\n            name=\"min_points\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        stat = arcpy.Parameter(\n            displayName=\"Correlation Statistic Type\",\n            name=\"stat\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        stat.filter.type = \"ValueList\"\n        stat.filter.list = ['pearson', 'kendall', 'spearman']\n        stat.value = 'pearson'\n\n        params = [i, field1, field2, radius, min_points, stat]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field1 = parameters[1].valueAsText\n        field2 = parameters[2].valueAsText\n        radius = parameters[3].valueAsText\n        min_points = parameters[4].valueAsText\n        stat = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.attribute_correlation_neighbourhood_analysis(i=i, field1=field1, field2=field2, radius=radius, min_points=min_points, stat=stat)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AttributeHistogram(object):\n    def __init__(self):\n        self.label = \"Attribute Histogram\"\n        self.description = \"Creates a histogram for the field values of a vector's attribute table.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [i, field, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.attribute_histogram(i=i, field=field, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AttributeScattergram(object):\n    def __init__(self):\n        self.label = \"Attribute Scattergram\"\n        self.description = \"Creates a scattergram for two field values of a vector's attribute table.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        fieldx = arcpy.Parameter(\n            displayName=\"Field Name X\",\n            name=\"fieldx\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        fieldx.parameterDependencies = [i.name]\n\n        fieldy = arcpy.Parameter(\n            displayName=\"Field Name Y\",\n            name=\"fieldy\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        fieldy.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        trendline = arcpy.Parameter(\n            displayName=\"Draw the trendline?\",\n            name=\"trendline\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        trendline.value = 'False'\n\n        params = [i, fieldx, fieldy, output, trendline]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        fieldx = parameters[1].valueAsText\n        fieldy = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        trendline = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.attribute_scattergram(i=i, fieldx=fieldx, fieldy=fieldy, output=output, trendline=trendline)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AverageFlowpathSlope(object):\n    def __init__(self):\n        self.label = \"Average Flowpath Slope\"\n        self.description = \"Measures the average slope gradient from each grid cell to all upslope divide cells.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.average_flowpath_slope(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AverageNormalVectorAngularDeviation(object):\n    def __init__(self):\n        self.label = \"Average Normal Vector Angular Deviation\"\n        self.description = \"Calculates the circular variance of aspect at a scale for a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Dimension\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '11'\n\n        params = [dem, output, filter]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.average_normal_vector_angular_deviation(dem=dem, output=output, filter=filter)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AverageOverlay(object):\n    def __init__(self):\n        self.label = \"Average Overlay\"\n        self.description = \"Calculates the average for each grid cell from a group of raster images.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.average_overlay(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AverageUpslopeFlowpathLength(object):\n    def __init__(self):\n        self.label = \"Average Upslope Flowpath Length\"\n        self.description = \"Measures the average length of all upslope flowpaths draining each grid cell.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.average_upslope_flowpath_length(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BalanceContrastEnhancement(object):\n    def __init__(self):\n        self.label = \"Balance Contrast Enhancement\"\n        self.description = \"Performs a balance contrast enhancement on a colour-composite image of multispectral data.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Colour Composite Image File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        band_mean = arcpy.Parameter(\n            displayName=\"Band Mean Value\",\n            name=\"band_mean\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        band_mean.value = '100.0'\n\n        params = [i, output, band_mean]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        band_mean = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.balance_contrast_enhancement(i=i, output=output, band_mean=band_mean)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Basins(object):\n    def __init__(self):\n        self.label = \"Basins\"\n        self.description = \"Identifies drainage basins that drain to the DEM edge.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        output = parameters[1].valueAsText\n        esri_pntr = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.basins(d8_pntr=d8_pntr, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BilateralFilter(object):\n    def __init__(self):\n        self.label = \"Bilateral Filter\"\n        self.description = \"A bilateral filter is an edge-preserving smoothing filter introduced by Tomasi and Manduchi (1998).\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        sigma_dist = arcpy.Parameter(\n            displayName=\"Distance Standard Deviation (pixels)\",\n            name=\"sigma_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma_dist.value = '0.75'\n\n        sigma_int = arcpy.Parameter(\n            displayName=\"Intensity Standard Deviation (intensity units)\",\n            name=\"sigma_int\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma_int.value = '1.0'\n\n        params = [i, output, sigma_dist, sigma_int]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        sigma_dist = parameters[2].valueAsText\n        sigma_int = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.bilateral_filter(i=i, output=output, sigma_dist=sigma_dist, sigma_int=sigma_int)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BlockMaximumGridding(object):\n    def __init__(self):\n        self.label = \"Block Maximum Gridding\"\n        self.description = \"Creates a raster grid based on a set of vector points and assigns grid values using a block maximum scheme.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        use_z = arcpy.Parameter(\n            displayName=\"Use z-coordinate instead of field?\",\n            name=\"use_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_z.value = 'False'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, use_z, output, cell_size, base]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        use_z = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        cell_size = parameters[4].valueAsText\n        base = parameters[5].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.block_maximum_gridding(i=i, field=field, use_z=use_z, output=output, cell_size=cell_size, base=base)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BlockMinimumGridding(object):\n    def __init__(self):\n        self.label = \"Block Minimum Gridding\"\n        self.description = \"Creates a raster grid based on a set of vector points and assigns grid values using a block minimum scheme.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        use_z = arcpy.Parameter(\n            displayName=\"Use z-coordinate instead of field?\",\n            name=\"use_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_z.value = 'False'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, use_z, output, cell_size, base]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        use_z = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        cell_size = parameters[4].valueAsText\n        base = parameters[5].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.block_minimum_gridding(i=i, field=field, use_z=use_z, output=output, cell_size=cell_size, base=base)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BoundaryShapeComplexity(object):\n    def __init__(self):\n        self.label = \"Boundary Shape Complexity\"\n        self.description = \"Calculates the complexity of the boundaries of raster polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.boundary_shape_complexity(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BreachDepressions(object):\n    def __init__(self):\n        self.label = \"Breach Depressions\"\n        self.description = \"Breaches all of the depressions in a DEM using Lindsay's (2016) algorithm. This should be preferred over depression filling in most cases.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        max_depth = arcpy.Parameter(\n            displayName=\"Maximum Breach Depth (z units)\",\n            name=\"max_depth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_length = arcpy.Parameter(\n            displayName=\"Maximum Breach Channel Length (grid cells)\",\n            name=\"max_length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        flat_increment = arcpy.Parameter(\n            displayName=\"Flat increment value (z units)\",\n            name=\"flat_increment\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        fill_pits = arcpy.Parameter(\n            displayName=\"Fill single-cell pits?\",\n            name=\"fill_pits\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        fill_pits.value = 'False'\n\n        params = [dem, output, max_depth, max_length, flat_increment, fill_pits]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        max_depth = parameters[2].valueAsText\n        max_length = parameters[3].valueAsText\n        flat_increment = parameters[4].valueAsText\n        fill_pits = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.breach_depressions(dem=dem, output=output, max_depth=max_depth, max_length=max_length, flat_increment=flat_increment, fill_pits=fill_pits)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BreachDepressionsLeastCost(object):\n    def __init__(self):\n        self.label = \"Breach Depressions Least Cost\"\n        self.description = \"Breaches the depressions in a DEM using a least-cost pathway method.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        dist = arcpy.Parameter(\n            displayName=\"Maximum Search Distance (cells)\",\n            name=\"dist\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        max_cost = arcpy.Parameter(\n            displayName=\"Maximum Breach Cost (z units)\",\n            name=\"max_cost\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        min_dist = arcpy.Parameter(\n            displayName=\"Minimize breach distances?\",\n            name=\"min_dist\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_dist.value = 'True'\n\n        flat_increment = arcpy.Parameter(\n            displayName=\"Flat increment value (z units)\",\n            name=\"flat_increment\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        fill = arcpy.Parameter(\n            displayName=\"Fill unbreached depressions?\",\n            name=\"fill\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        fill.value = 'True'\n\n        params = [dem, output, dist, max_cost, min_dist, flat_increment, fill]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        dist = parameters[2].valueAsText\n        max_cost = parameters[3].valueAsText\n        min_dist = parameters[4].valueAsText\n        flat_increment = parameters[5].valueAsText\n        fill = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.breach_depressions_least_cost(dem=dem, output=output, dist=dist, max_cost=max_cost, min_dist=min_dist, flat_increment=flat_increment, fill=fill)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BreachSingleCellPits(object):\n    def __init__(self):\n        self.label = \"Breach Single Cell Pits\"\n        self.description = \"Removes single-cell pits from an input DEM by breaching.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.breach_single_cell_pits(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BreaklineMapping(object):\n    def __init__(self):\n        self.label = \"Breakline Mapping\"\n        self.description = \"This tool maps breaklines from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector Lines File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        threshold = arcpy.Parameter(\n            displayName=\"Threshold Value\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        threshold.value = '2.0'\n\n        min_length = arcpy.Parameter(\n            displayName=\"Min. Line Length (In Grid Cells)\",\n            name=\"min_length\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_length.value = '3'\n\n        params = [dem, output, threshold, min_length]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        threshold = parameters[2].valueAsText\n        min_length = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.breakline_mapping(dem=dem, output=output, threshold=threshold, min_length=min_length)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BufferRaster(object):\n    def __init__(self):\n        self.label = \"Buffer Raster\"\n        self.description = \"Maps a distance-based buffer around each non-background (non-zero/non-nodata) grid cell in an input image.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        size = arcpy.Parameter(\n            displayName=\"Buffer Size\",\n            name=\"size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        gridcells = arcpy.Parameter(\n            displayName=\"Buffer size measured in grid cells?\",\n            name=\"gridcells\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, size, gridcells]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        size = parameters[2].valueAsText\n        gridcells = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.buffer_raster(i=i, output=output, size=size, gridcells=gridcells)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BurnStreamsAtRoads(object):\n    def __init__(self):\n        self.label = \"Burn Streams At Roads\"\n        self.description = \"Burns-in streams at the sites of road embankments.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Vector Streams File\",\n            name=\"streams\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        streams.filter.list = [\"Polyline\"]\n\n        roads = arcpy.Parameter(\n            displayName=\"Input Vector Roads File\",\n            name=\"roads\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        roads.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        width = arcpy.Parameter(\n            displayName=\"Road Embankment Width\",\n            name=\"width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, streams, roads, output, width]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        roads = parameters[2].valueAsText\n        if roads is not None:\n            desc = arcpy.Describe(roads)\n            roads = desc.catalogPath\n        output = parameters[3].valueAsText\n        width = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.burn_streams_at_roads(dem=dem, streams=streams, roads=roads, output=output, width=width)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CannyEdgeDetection(object):\n    def __init__(self):\n        self.label = \"Canny Edge Detection\"\n        self.description = \"This tool performs a Canny edge-detection filter on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster Image\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        sigma = arcpy.Parameter(\n            displayName=\"Sigma Value\",\n            name=\"sigma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma.value = '0.5'\n\n        low = arcpy.Parameter(\n            displayName=\"Low Threshold\",\n            name=\"low\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        low.value = '0.05'\n\n        high = arcpy.Parameter(\n            displayName=\"High Threshold\",\n            name=\"high\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        high.value = '0.15'\n\n        add_back = arcpy.Parameter(\n            displayName=\"Add edge back to the image?\",\n            name=\"add_back\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        add_back.value = 'False'\n\n        params = [i, output, sigma, low, high, add_back]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        sigma = parameters[2].valueAsText\n        low = parameters[3].valueAsText\n        high = parameters[4].valueAsText\n        add_back = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.canny_edge_detection(i=i, output=output, sigma=sigma, low=low, high=high, add_back=add_back)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Ceil(object):\n    def __init__(self):\n        self.label = \"Ceil\"\n        self.description = \"Returns the smallest (closest to negative infinity) value that is greater than or equal to the values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.ceil(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Centroid(object):\n    def __init__(self):\n        self.label = \"Centroid\"\n        self.description = \"Calculates the centroid, or average location, of raster polygon objects.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        text_output = arcpy.Parameter(\n            displayName=\"Output text?\",\n            name=\"text_output\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, output, text_output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        text_output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.centroid(i=i, output=output, text_output=text_output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CentroidVector(object):\n    def __init__(self):\n        self.label = \"Centroid Vector\"\n        self.description = \"Identifies the centroid point of a vector polyline or polygon feature or a group of vector points.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.centroid_vector(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ChangeVectorAnalysis(object):\n    def __init__(self):\n        self.label = \"Change Vector Analysis\"\n        self.description = \"Performs a change vector analysis on a two-date multi-spectral dataset.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        date1 = arcpy.Parameter(\n            displayName=\"Earlier Date Input Files\",\n            name=\"date1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        date1.multiValue = True\n\n        date2 = arcpy.Parameter(\n            displayName=\"Later Date Input Files\",\n            name=\"date2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        date2.multiValue = True\n\n        magnitude = arcpy.Parameter(\n            displayName=\"Output Vector Magnitude File\",\n            name=\"magnitude\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        magnitude.filter.list = [\"tif\"]\n\n        direction = arcpy.Parameter(\n            displayName=\"Output Vector Direction File\",\n            name=\"direction\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        direction.filter.list = [\"tif\"]\n\n        params = [date1, date2, magnitude, direction]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        date1 = parameters[0].valueAsText\n        if date1 is not None:\n            items = date1.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            date1 = \";\".join(items_path)\n        date2 = parameters[1].valueAsText\n        if date2 is not None:\n            items = date2.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            date2 = \";\".join(items_path)\n        magnitude = parameters[2].valueAsText\n        direction = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.change_vector_analysis(date1=date1, date2=date2, magnitude=magnitude, direction=direction)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CircularVarianceOfAspect(object):\n    def __init__(self):\n        self.label = \"Circular Variance Of Aspect\"\n        self.description = \"Calculates the circular variance of aspect at a scale for a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Dimension\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '11'\n\n        params = [dem, output, filter]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.circular_variance_of_aspect(dem=dem, output=output, filter=filter)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ClassifyBuildingsInLidar(object):\n    def __init__(self):\n        self.label = \"Classify Buildings In Lidar\"\n        self.description = \"Reclassifies a LiDAR points that lie within vector building footprints.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        buildings = arcpy.Parameter(\n            displayName=\"Input Building Polygon File\",\n            name=\"buildings\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        buildings.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, buildings, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        buildings = parameters[1].valueAsText\n        if buildings is not None:\n            desc = arcpy.Describe(buildings)\n            buildings = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.classify_buildings_in_lidar(i=i, buildings=buildings, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ClassifyLidar(object):\n    def __init__(self):\n        self.label = \"Classify Lidar\"\n        self.description = \"Classify points within a LiDAR point cloud based on point properties.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR Points\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Distance:\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '1.5'\n\n        grd_threshold = arcpy.Parameter(\n            displayName=\"Ground Threshold:\",\n            name=\"grd_threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        grd_threshold.value = '0.1'\n\n        oto_threshold = arcpy.Parameter(\n            displayName=\"Off-Terrain Object Threshold:\",\n            name=\"oto_threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        oto_threshold.value = '2.0'\n\n        planarity_threshold = arcpy.Parameter(\n            displayName=\"Planarity Threshold:\",\n            name=\"planarity_threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        planarity_threshold.value = '0.85'\n\n        linearity_threshold = arcpy.Parameter(\n            displayName=\"Linearity Threshold:\",\n            name=\"linearity_threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        linearity_threshold.value = '0.70'\n\n        iterations = arcpy.Parameter(\n            displayName=\"Number of Iterations:\",\n            name=\"iterations\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        iterations.value = '30'\n\n        facade_threshold = arcpy.Parameter(\n            displayName=\"Facade Threshold:\",\n            name=\"facade_threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        facade_threshold.value = '0.5'\n\n        params = [i, output, radius, grd_threshold, oto_threshold, planarity_threshold, linearity_threshold, iterations, facade_threshold]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        radius = parameters[2].valueAsText\n        grd_threshold = parameters[3].valueAsText\n        oto_threshold = parameters[4].valueAsText\n        planarity_threshold = parameters[5].valueAsText\n        linearity_threshold = parameters[6].valueAsText\n        iterations = parameters[7].valueAsText\n        facade_threshold = parameters[8].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.classify_lidar(i=i, output=output, radius=radius, grd_threshold=grd_threshold, oto_threshold=oto_threshold, planarity_threshold=planarity_threshold, linearity_threshold=linearity_threshold, iterations=iterations, facade_threshold=facade_threshold)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ClassifyOverlapPoints(object):\n    def __init__(self):\n        self.label = \"Classify Overlap Points\"\n        self.description = \"Classifies or filters LAS points in regions of overlapping flight lines.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        resolution = arcpy.Parameter(\n            displayName=\"Sample Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '2.0'\n\n        criterion = arcpy.Parameter(\n            displayName=\"Overlap Criterion\",\n            name=\"criterion\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        criterion.filter.type = \"ValueList\"\n        criterion.filter.list = ['max scan angle', 'not min point source ID', 'not min time', 'multiple point source IDs']\n        criterion.value = 'max scan angle'\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter out points from overlapping flightlines?\",\n            name=\"filter\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = 'False'\n\n        params = [i, output, resolution, criterion, filter]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        resolution = parameters[2].valueAsText\n        criterion = parameters[3].valueAsText\n        filter = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.classify_overlap_points(i=i, output=output, resolution=resolution, criterion=criterion, filter=filter)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CleanVector(object):\n    def __init__(self):\n        self.label = \"Clean Vector\"\n        self.description = \"Removes null features and lines/polygons with fewer than the required number of vertices.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.clean_vector(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Clip(object):\n    def __init__(self):\n        self.label = \"Clip\"\n        self.description = \"Extract all the features, or parts of features, that overlap with the features of the clip vector.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        clip = arcpy.Parameter(\n            displayName=\"Input Clip Polygon Vector File\",\n            name=\"clip\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        clip.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, clip, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        clip = parameters[1].valueAsText\n        if clip is not None:\n            desc = arcpy.Describe(clip)\n            clip = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.clip(i=i, clip=clip, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ClipLidarToPolygon(object):\n    def __init__(self):\n        self.label = \"Clip Lidar To Polygon\"\n        self.description = \"Clips a LiDAR point cloud to a vector polygon or polygons.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        polygons = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"polygons\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        polygons.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, polygons, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        polygons = parameters[1].valueAsText\n        if polygons is not None:\n            desc = arcpy.Describe(polygons)\n            polygons = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.clip_lidar_to_polygon(i=i, polygons=polygons, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ClipRasterToPolygon(object):\n    def __init__(self):\n        self.label = \"Clip Raster To Polygon\"\n        self.description = \"Clips a raster to a vector polygon.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        polygons = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"polygons\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        polygons.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        maintain_dimensions = arcpy.Parameter(\n            displayName=\"Maintain input raster dimensions?\",\n            name=\"maintain_dimensions\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        maintain_dimensions.value = 'False'\n\n        params = [i, polygons, output, maintain_dimensions]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        polygons = parameters[1].valueAsText\n        if polygons is not None:\n            desc = arcpy.Describe(polygons)\n            polygons = desc.catalogPath\n        output = parameters[2].valueAsText\n        maintain_dimensions = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.clip_raster_to_polygon(i=i, polygons=polygons, output=output, maintain_dimensions=maintain_dimensions)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Closing(object):\n    def __init__(self):\n        self.label = \"Closing\"\n        self.description = \"A closing is a mathematical morphology operation involving an erosion (min filter) of a dilation (max filter) set.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.closing(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Clump(object):\n    def __init__(self):\n        self.label = \"Clump\"\n        self.description = \"Groups cells that form discrete areas, assigning them unique identifiers.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        diag = arcpy.Parameter(\n            displayName=\"Include diagonal connections?\",\n            name=\"diag\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        diag.value = 'True'\n\n        zero_back = arcpy.Parameter(\n            displayName=\"Treat zero values as background?\",\n            name=\"zero_back\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, output, diag, zero_back]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        diag = parameters[2].valueAsText\n        zero_back = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.clump(i=i, output=output, diag=diag, zero_back=zero_back)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ColourizeBasedOnClass(object):\n    def __init__(self):\n        self.label = \"Colourize Based On Class\"\n        self.description = \"Sets the RGB values of a LiDAR point cloud based on the point classification values.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR Points\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        intensity_blending = arcpy.Parameter(\n            displayName=\"Intensity Blending Amount (0-100%):\",\n            name=\"intensity_blending\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        intensity_blending.value = '50.0'\n\n        clr_str = arcpy.Parameter(\n            displayName=\"Colour values:\",\n            name=\"clr_str\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_unique_clrs_for_buildings = arcpy.Parameter(\n            displayName=\"Use unique colours for each building?\",\n            name=\"use_unique_clrs_for_buildings\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_unique_clrs_for_buildings.value = 'False'\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Distance:\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        params = [i, output, intensity_blending, clr_str, use_unique_clrs_for_buildings, radius]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        intensity_blending = parameters[2].valueAsText\n        clr_str = parameters[3].valueAsText\n        use_unique_clrs_for_buildings = parameters[4].valueAsText\n        radius = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.colourize_based_on_class(i=i, output=output, intensity_blending=intensity_blending, clr_str=clr_str, use_unique_clrs_for_buildings=use_unique_clrs_for_buildings, radius=radius)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ColourizeBasedOnPointReturns(object):\n    def __init__(self):\n        self.label = \"Colourize Based On Point Returns\"\n        self.description = \"Sets the RGB values of a LiDAR point cloud based on the point returns.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR Points\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        intensity_blending = arcpy.Parameter(\n            displayName=\"Intensity Blending Amount (0-100%):\",\n            name=\"intensity_blending\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        intensity_blending.value = '50.0'\n\n        only = arcpy.Parameter(\n            displayName=\"Only Return Colour\",\n            name=\"only\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        only.value = '(230,214,170)'\n\n        first = arcpy.Parameter(\n            displayName=\"First Return Colour\",\n            name=\"first\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        first.value = '(0,140,0)'\n\n        intermediate = arcpy.Parameter(\n            displayName=\"Intermediate Return Colour\",\n            name=\"intermediate\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        intermediate.value = '(255,0,255)'\n\n        last = arcpy.Parameter(\n            displayName=\"Last Return Colour\",\n            name=\"last\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        last.value = '(0,0,255)'\n\n        params = [i, output, intensity_blending, only, first, intermediate, last]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        intensity_blending = parameters[2].valueAsText\n        only = parameters[3].valueAsText\n        first = parameters[4].valueAsText\n        intermediate = parameters[5].valueAsText\n        last = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.colourize_based_on_point_returns(i=i, output=output, intensity_blending=intensity_blending, only=only, first=first, intermediate=intermediate, last=last)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CompactnessRatio(object):\n    def __init__(self):\n        self.label = \"Compactness Ratio\"\n        self.description = \"Calculates the compactness ratio (A/P), a measure of shape complexity, for vector polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.compactness_ratio(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ConditionalEvaluation(object):\n    def __init__(self):\n        self.label = \"Conditional Evaluation\"\n        self.description = \"Performs a conditional evaluation (if-then-else) operation on a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        statement = arcpy.Parameter(\n            displayName=\"Conditional Statement e.g. value > 35.0:\",\n            name=\"statement\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        true = arcpy.Parameter(\n            displayName=\"Value Where TRUE (Raster File Or Constant Value)\",\n            name=\"true\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        false = arcpy.Parameter(\n            displayName=\"Value Where FALSE (Raster File Or Constant Value)\",\n            name=\"false\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, statement, true, false, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        statement = parameters[1].valueAsText\n        true = parameters[2].valueAsText\n        if true is not None:\n            try:\n                true = str(float(true))\n            except:\n                desc = arcpy.Describe(true)\n                true = desc.catalogPath\n        false = parameters[3].valueAsText\n        if false is not None:\n            try:\n                false = str(float(false))\n            except:\n                desc = arcpy.Describe(false)\n                false = desc.catalogPath\n        output = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.conditional_evaluation(i=i, statement=statement, true=true, false=false, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ConditionedLatinHypercube(object):\n    def __init__(self):\n        self.label = \"Conditioned Latin Hypercube\"\n        self.description = \"Implements conditioned Latin Hypercube sampling.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Raster\",\n            name=\"inputs\",\n            datatype=[\"DERasterDataset\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output shapefile\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        samples = arcpy.Parameter(\n            displayName=\"Number of sample sites\",\n            name=\"samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        samples.value = '500'\n\n        iterations = arcpy.Parameter(\n            displayName=\"Number of resampling iterations\",\n            name=\"iterations\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        iterations.value = '25000'\n\n        seed = arcpy.Parameter(\n            displayName=\"RNG seed\",\n            name=\"seed\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        prob = arcpy.Parameter(\n            displayName=\"Random resample probability\",\n            name=\"prob\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        prob.value = '0.5'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Objective function threshold.\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        temp = arcpy.Parameter(\n            displayName=\"Initial annealing temperature\",\n            name=\"temp\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        temp.value = '1.0'\n\n        temp_decay = arcpy.Parameter(\n            displayName=\"Temperature decay factor\",\n            name=\"temp_decay\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        temp_decay.value = '0.05'\n\n        cycle = arcpy.Parameter(\n            displayName=\"Annealing cycle duration\",\n            name=\"cycle\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        cycle.value = '10'\n\n        average = arcpy.Parameter(\n            displayName=\"Average the continuous Obj. Func.\",\n            name=\"average\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        average.value = 'False'\n\n        params = [inputs, output, samples, iterations, seed, prob, threshold, temp, temp_decay, cycle, average]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        samples = parameters[2].valueAsText\n        iterations = parameters[3].valueAsText\n        seed = parameters[4].valueAsText\n        prob = parameters[5].valueAsText\n        threshold = parameters[6].valueAsText\n        temp = parameters[7].valueAsText\n        temp_decay = parameters[8].valueAsText\n        cycle = parameters[9].valueAsText\n        average = parameters[10].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.conditioned_latin_hypercube(inputs=inputs, output=output, samples=samples, iterations=iterations, seed=seed, prob=prob, threshold=threshold, temp=temp, temp_decay=temp_decay, cycle=cycle, average=average)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ConservativeSmoothingFilter(object):\n    def __init__(self):\n        self.label = \"Conservative Smoothing Filter\"\n        self.description = \"Performs a conservative-smoothing filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '3'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '3'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.conservative_smoothing_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ConstructVectorTin(object):\n    def __init__(self):\n        self.label = \"Construct Vector Tin\"\n        self.description = \"Creates a vector triangular irregular network (TIN) for a set of vector points.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        use_z = arcpy.Parameter(\n            displayName=\"Use Shapefile 'z' values?\",\n            name=\"use_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_z.value = 'False'\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        max_triangle_edge_length = arcpy.Parameter(\n            displayName=\"Maximum Triangle Edge Length (optional)\",\n            name=\"max_triangle_edge_length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, use_z, output, max_triangle_edge_length]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        use_z = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        max_triangle_edge_length = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.construct_vector_tin(i=i, field=field, use_z=use_z, output=output, max_triangle_edge_length=max_triangle_edge_length)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ContoursFromPoints(object):\n    def __init__(self):\n        self.label = \"Contours From Points\"\n        self.description = \"Creates a contour coverage from a set of input points.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        use_z = arcpy.Parameter(\n            displayName=\"Use Shapefile 'z' values?\",\n            name=\"use_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_z.value = 'False'\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector Lines File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        max_triangle_edge_length = arcpy.Parameter(\n            displayName=\"Maximum Triangle Edge Length (optional)\",\n            name=\"max_triangle_edge_length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        interval = arcpy.Parameter(\n            displayName=\"Contour Interval\",\n            name=\"interval\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        interval.value = '10.0'\n\n        base = arcpy.Parameter(\n            displayName=\"Base Contour\",\n            name=\"base\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        base.value = '0.0'\n\n        smooth = arcpy.Parameter(\n            displayName=\"Smoothing Filter Size\",\n            name=\"smooth\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        smooth.value = '5'\n\n        params = [i, field, use_z, output, max_triangle_edge_length, interval, base, smooth]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        use_z = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        max_triangle_edge_length = parameters[4].valueAsText\n        interval = parameters[5].valueAsText\n        base = parameters[6].valueAsText\n        smooth = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.contours_from_points(i=i, field=field, use_z=use_z, output=output, max_triangle_edge_length=max_triangle_edge_length, interval=interval, base=base, smooth=smooth)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ContoursFromRaster(object):\n    def __init__(self):\n        self.label = \"Contours From Raster\"\n        self.description = \"Derives a vector contour coverage from a raster surface.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster Surface File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Contour File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        interval = arcpy.Parameter(\n            displayName=\"Contour Interval\",\n            name=\"interval\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        interval.value = '10.0'\n\n        base = arcpy.Parameter(\n            displayName=\"Base Contour\",\n            name=\"base\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        base.value = '0.0'\n\n        smooth = arcpy.Parameter(\n            displayName=\"Smoothing Filter Size\",\n            name=\"smooth\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        smooth.value = '9'\n\n        tolerance = arcpy.Parameter(\n            displayName=\"Tolerance\",\n            name=\"tolerance\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        tolerance.value = '10.0'\n\n        params = [i, output, interval, base, smooth, tolerance]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        interval = parameters[2].valueAsText\n        base = parameters[3].valueAsText\n        smooth = parameters[4].valueAsText\n        tolerance = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.contours_from_raster(i=i, output=output, interval=interval, base=base, smooth=smooth, tolerance=tolerance)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ConvertNodataToZero(object):\n    def __init__(self):\n        self.label = \"Convert Nodata To Zero\"\n        self.description = \"Converts nodata values in a raster to zero.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.convert_nodata_to_zero(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ConvertRasterFormat(object):\n    def __init__(self):\n        self.label = \"Convert Raster Format\"\n        self.description = \"Converts raster data from one format to another.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.convert_raster_format(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CornerDetection(object):\n    def __init__(self):\n        self.label = \"Corner Detection\"\n        self.description = \"Identifies corner patterns in boolean images using hit-and-miss pattern matching.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.corner_detection(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CorrectVignetting(object):\n    def __init__(self):\n        self.label = \"Correct Vignetting\"\n        self.description = \"Corrects the darkening of images towards corners.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        pp = arcpy.Parameter(\n            displayName=\"Input Principal Point File\",\n            name=\"pp\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        pp.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        focal_length = arcpy.Parameter(\n            displayName=\"Camera Focal Length (mm)\",\n            name=\"focal_length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        focal_length.value = '304.8'\n\n        image_width = arcpy.Parameter(\n            displayName=\"Distance Between Left-Right Edges (mm)\",\n            name=\"image_width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        image_width.value = '228.6'\n\n        n = arcpy.Parameter(\n            displayName=\"n Parameter\",\n            name=\"n\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        n.value = '4.0'\n\n        params = [i, pp, output, focal_length, image_width, n]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        pp = parameters[1].valueAsText\n        if pp is not None:\n            desc = arcpy.Describe(pp)\n            pp = desc.catalogPath\n        output = parameters[2].valueAsText\n        focal_length = parameters[3].valueAsText\n        image_width = parameters[4].valueAsText\n        n = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.correct_vignetting(i=i, pp=pp, output=output, focal_length=focal_length, image_width=image_width, n=n)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Cos(object):\n    def __init__(self):\n        self.label = \"Cos\"\n        self.description = \"Returns the cosine (cos) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.cos(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Cosh(object):\n    def __init__(self):\n        self.label = \"Cosh\"\n        self.description = \"Returns the hyperbolic cosine (cosh) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.cosh(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CostAllocation(object):\n    def __init__(self):\n        self.label = \"Cost Allocation\"\n        self.description = \"Identifies the source cell to which each grid cell is connected by a least-cost pathway in a cost-distance analysis.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        source = arcpy.Parameter(\n            displayName=\"Input Source File\",\n            name=\"source\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        backlink = arcpy.Parameter(\n            displayName=\"Input Backlink File\",\n            name=\"backlink\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [source, backlink, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        source = parameters[0].valueAsText\n        if source is not None:\n            desc = arcpy.Describe(source)\n            source = desc.catalogPath\n        backlink = parameters[1].valueAsText\n        if backlink is not None:\n            desc = arcpy.Describe(backlink)\n            backlink = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.cost_allocation(source=source, backlink=backlink, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CostDistance(object):\n    def __init__(self):\n        self.label = \"Cost Distance\"\n        self.description = \"Performs cost-distance accumulation on a cost surface and a group of source cells.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        source = arcpy.Parameter(\n            displayName=\"Input Source File\",\n            name=\"source\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        cost = arcpy.Parameter(\n            displayName=\"Input Cost (Friction) File\",\n            name=\"cost\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_accum = arcpy.Parameter(\n            displayName=\"Output Cost Accumulation File\",\n            name=\"out_accum\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_accum.filter.list = [\"tif\"]\n\n        out_backlink = arcpy.Parameter(\n            displayName=\"Output Backlink File\",\n            name=\"out_backlink\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_backlink.filter.list = [\"tif\"]\n\n        params = [source, cost, out_accum, out_backlink]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        source = parameters[0].valueAsText\n        if source is not None:\n            desc = arcpy.Describe(source)\n            source = desc.catalogPath\n        cost = parameters[1].valueAsText\n        if cost is not None:\n            desc = arcpy.Describe(cost)\n            cost = desc.catalogPath\n        out_accum = parameters[2].valueAsText\n        out_backlink = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.cost_distance(source=source, cost=cost, out_accum=out_accum, out_backlink=out_backlink)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CostPathway(object):\n    def __init__(self):\n        self.label = \"Cost Pathway\"\n        self.description = \"Performs cost-distance pathway analysis using a series of destination grid cells.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        destination = arcpy.Parameter(\n            displayName=\"Input Destination File\",\n            name=\"destination\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        backlink = arcpy.Parameter(\n            displayName=\"Input Backlink File\",\n            name=\"backlink\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Treat zero values as background?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [destination, backlink, output, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        destination = parameters[0].valueAsText\n        if destination is not None:\n            desc = arcpy.Describe(destination)\n            destination = desc.catalogPath\n        backlink = parameters[1].valueAsText\n        if backlink is not None:\n            desc = arcpy.Describe(backlink)\n            backlink = desc.catalogPath\n        output = parameters[2].valueAsText\n        zero_background = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.cost_pathway(destination=destination, backlink=backlink, output=output, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CountIf(object):\n    def __init__(self):\n        self.label = \"Count If\"\n        self.description = \"Counts the number of occurrences of a specified value in a cell-stack of rasters.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        value = arcpy.Parameter(\n            displayName=\"Value\",\n            name=\"value\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [inputs, output, value]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        value = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.count_if(inputs=inputs, output=output, value=value)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CreateColourComposite(object):\n    def __init__(self):\n        self.label = \"Create Colour Composite\"\n        self.description = \"Creates a colour-composite image from three bands of multispectral imagery.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        red = arcpy.Parameter(\n            displayName=\"Input Red Band Image File\",\n            name=\"red\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        green = arcpy.Parameter(\n            displayName=\"Input Green Band Image File\",\n            name=\"green\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        blue = arcpy.Parameter(\n            displayName=\"Input Blue Band Image File\",\n            name=\"blue\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        opacity = arcpy.Parameter(\n            displayName=\"Input Opacity Band Image File (Optional)\",\n            name=\"opacity\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Colour Composite File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        enhance = arcpy.Parameter(\n            displayName=\"Perform balance contrast enhancement?\",\n            name=\"enhance\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        enhance.value = 'True'\n\n        zeros = arcpy.Parameter(\n            displayName=\"Treat zeros as nodata?\",\n            name=\"zeros\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zeros.value = 'False'\n\n        params = [red, green, blue, opacity, output, enhance, zeros]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        red = parameters[0].valueAsText\n        if red is not None:\n            desc = arcpy.Describe(red)\n            red = desc.catalogPath\n        green = parameters[1].valueAsText\n        if green is not None:\n            desc = arcpy.Describe(green)\n            green = desc.catalogPath\n        blue = parameters[2].valueAsText\n        if blue is not None:\n            desc = arcpy.Describe(blue)\n            blue = desc.catalogPath\n        opacity = parameters[3].valueAsText\n        if opacity is not None:\n            desc = arcpy.Describe(opacity)\n            opacity = desc.catalogPath\n        output = parameters[4].valueAsText\n        enhance = parameters[5].valueAsText\n        zeros = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.create_colour_composite(red=red, green=green, blue=blue, opacity=opacity, output=output, enhance=enhance, zeros=zeros)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CreateHexagonalVectorGrid(object):\n    def __init__(self):\n        self.label = \"Create Hexagonal Vector Grid\"\n        self.description = \"Creates a hexagonal vector grid.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        input = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"input\",\n            datatype=[\"DERasterDataset\", \"DEShapefile\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        width = arcpy.Parameter(\n            displayName=\"Hexagon Width\",\n            name=\"width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        orientation = arcpy.Parameter(\n            displayName=\"Grid Orientation\",\n            name=\"orientation\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        orientation.filter.type = \"ValueList\"\n        orientation.filter.list = ['horizontal', 'vertical']\n        orientation.value = 'horizontal'\n\n        params = [input, output, width, orientation]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        width = parameters[2].valueAsText\n        orientation = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.create_hexagonal_vector_grid(i=i, output=output, width=width, orientation=orientation)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CreatePlane(object):\n    def __init__(self):\n        self.label = \"Create Plane\"\n        self.description = \"Creates a raster image based on the equation for a simple plane.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        base = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        gradient = arcpy.Parameter(\n            displayName=\"Gradient\",\n            name=\"gradient\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        gradient.value = '15.0'\n\n        aspect = arcpy.Parameter(\n            displayName=\"Aspect\",\n            name=\"aspect\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        aspect.value = '90.0'\n\n        constant = arcpy.Parameter(\n            displayName=\"Constant\",\n            name=\"constant\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        constant.value = '0.0'\n\n        params = [base, output, gradient, aspect, constant]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        base = parameters[0].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        output = parameters[1].valueAsText\n        gradient = parameters[2].valueAsText\n        aspect = parameters[3].valueAsText\n        constant = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.create_plane(base=base, output=output, gradient=gradient, aspect=aspect, constant=constant)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CreateRectangularVectorGrid(object):\n    def __init__(self):\n        self.label = \"Create Rectangular Vector Grid\"\n        self.description = \"Creates a rectangular vector grid.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        input = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"input\",\n            datatype=[\"DERasterDataset\", \"DEShapefile\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        width = arcpy.Parameter(\n            displayName=\"Grid Cell Width\",\n            name=\"width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        height = arcpy.Parameter(\n            displayName=\"Grid Cell Height\",\n            name=\"height\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        xorig = arcpy.Parameter(\n            displayName=\"Grid origin x-coordinate\",\n            name=\"xorig\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        xorig.value = '0'\n\n        yorig = arcpy.Parameter(\n            displayName=\"Grid origin y-coordinate\",\n            name=\"yorig\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        yorig.value = '0'\n\n        params = [input, output, width, height, xorig, yorig]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        width = parameters[2].valueAsText\n        height = parameters[3].valueAsText\n        xorig = parameters[4].valueAsText\n        yorig = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.create_rectangular_vector_grid(i=i, output=output, width=width, height=height, xorig=xorig, yorig=yorig)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CrispnessIndex(object):\n    def __init__(self):\n        self.label = \"Crispness Index\"\n        self.description = \"Calculates the Crispness Index, which is used to quantify how crisp (or conversely how fuzzy) a probability image is.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.crispness_index(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CrossTabulation(object):\n    def __init__(self):\n        self.label = \"Cross Tabulation\"\n        self.description = \"Performs a cross-tabulation on two categorical images.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File 1\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File 2\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.cross_tabulation(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CsvPointsToVector(object):\n    def __init__(self):\n        self.label = \"Csv Points To Vector\"\n        self.description = \"Converts a CSV text file to vector points.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input CSV File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"csv\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        xfield = arcpy.Parameter(\n            displayName=\"X Field Number (zero-based)\",\n            name=\"xfield\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        xfield.value = '0'\n\n        yfield = arcpy.Parameter(\n            displayName=\"Y Field Number (zero-based)\",\n            name=\"yfield\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        yfield.value = '1'\n\n        epsg = arcpy.Parameter(\n            displayName=\"EPSG Projection\",\n            name=\"epsg\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, xfield, yfield, epsg]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        xfield = parameters[2].valueAsText\n        yfield = parameters[3].valueAsText\n        epsg = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.csv_points_to_vector(i=i, output=output, xfield=xfield, yfield=yfield, epsg=epsg)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CumulativeDistribution(object):\n    def __init__(self):\n        self.label = \"Cumulative Distribution\"\n        self.description = \"Converts a raster image to its cumulative distribution function.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.cumulative_distribution(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Curvedness(object):\n    def __init__(self):\n        self.label = \"Curvedness\"\n        self.description = \"This tool calculates curvedness from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.curvedness(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass D8FlowAccumulation(object):\n    def __init__(self):\n        self.label = \"D8 Flow Accumulation\"\n        self.description = \"Calculates a D8 flow accumulation raster from an input DEM or flow pointer.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input DEM or D8 Pointer File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['cells', 'catchment area', 'specific contributing area']\n        out_type.value = 'cells'\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip the upper tail by 1%?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        pntr = arcpy.Parameter(\n            displayName=\"Is the input raster a D8 flow pointer?\",\n            name=\"pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"If a pointer is input, does it use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [i, output, out_type, log, clip, pntr, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_type = parameters[2].valueAsText\n        log = parameters[3].valueAsText\n        clip = parameters[4].valueAsText\n        pntr = parameters[5].valueAsText\n        esri_pntr = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.d8_flow_accumulation(i=i, output=output, out_type=out_type, log=log, clip=clip, pntr=pntr, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass D8MassFlux(object):\n    def __init__(self):\n        self.label = \"D8 Mass Flux\"\n        self.description = \"Performs a D8 mass flux calculation.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        loading = arcpy.Parameter(\n            displayName=\"Input Loading File\",\n            name=\"loading\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        efficiency = arcpy.Parameter(\n            displayName=\"Input Efficiency File\",\n            name=\"efficiency\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        absorption = arcpy.Parameter(\n            displayName=\"Input Absorption File\",\n            name=\"absorption\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, loading, efficiency, absorption, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        loading = parameters[1].valueAsText\n        if loading is not None:\n            desc = arcpy.Describe(loading)\n            loading = desc.catalogPath\n        efficiency = parameters[2].valueAsText\n        if efficiency is not None:\n            desc = arcpy.Describe(efficiency)\n            efficiency = desc.catalogPath\n        absorption = parameters[3].valueAsText\n        if absorption is not None:\n            desc = arcpy.Describe(absorption)\n            absorption = desc.catalogPath\n        output = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.d8_mass_flux(dem=dem, loading=loading, efficiency=efficiency, absorption=absorption, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass D8Pointer(object):\n    def __init__(self):\n        self.label = \"D8 Pointer\"\n        self.description = \"Calculates a D8 flow pointer raster from an input DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Should the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [dem, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        esri_pntr = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.d8_pointer(dem=dem, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DInfFlowAccumulation(object):\n    def __init__(self):\n        self.label = \"D Inf Flow Accumulation\"\n        self.description = \"Calculates a D-infinity flow accumulation raster from an input DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input DEM or D-inf Pointer File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['Cells', 'Specific Contributing Area', 'Catchment Area']\n        out_type.value = 'Specific Contributing Area'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Convergence Threshold (grid cells; blank for none)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip the upper tail by 1%?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        pntr = arcpy.Parameter(\n            displayName=\"Is the input raster a D-inf flow pointer?\",\n            name=\"pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, out_type, threshold, log, clip, pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_type = parameters[2].valueAsText\n        threshold = parameters[3].valueAsText\n        log = parameters[4].valueAsText\n        clip = parameters[5].valueAsText\n        pntr = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.d_inf_flow_accumulation(i=i, output=output, out_type=out_type, threshold=threshold, log=log, clip=clip, pntr=pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DInfMassFlux(object):\n    def __init__(self):\n        self.label = \"D Inf Mass Flux\"\n        self.description = \"Performs a D-infinity mass flux calculation.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        loading = arcpy.Parameter(\n            displayName=\"Input Loading File\",\n            name=\"loading\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        efficiency = arcpy.Parameter(\n            displayName=\"Input Efficiency File\",\n            name=\"efficiency\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        absorption = arcpy.Parameter(\n            displayName=\"Input Absorption File\",\n            name=\"absorption\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, loading, efficiency, absorption, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        loading = parameters[1].valueAsText\n        if loading is not None:\n            desc = arcpy.Describe(loading)\n            loading = desc.catalogPath\n        efficiency = parameters[2].valueAsText\n        if efficiency is not None:\n            desc = arcpy.Describe(efficiency)\n            efficiency = desc.catalogPath\n        absorption = parameters[3].valueAsText\n        if absorption is not None:\n            desc = arcpy.Describe(absorption)\n            absorption = desc.catalogPath\n        output = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.d_inf_mass_flux(dem=dem, loading=loading, efficiency=efficiency, absorption=absorption, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DInfPointer(object):\n    def __init__(self):\n        self.label = \"D Inf Pointer\"\n        self.description = \"Calculates a D-infinity flow pointer (flow direction) raster from an input DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.d_inf_pointer(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Dbscan(object):\n    def __init__(self):\n        self.label = \"Dbscan\"\n        self.description = \"Performs a DBSCAN-based unsupervised clustering operation.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Rasters\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        scaling = arcpy.Parameter(\n            displayName=\"Scaling Method\",\n            name=\"scaling\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        scaling.filter.type = \"ValueList\"\n        scaling.filter.list = ['None', 'Normalize', 'Standardize']\n        scaling.value = 'Normalize'\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        search_dist = arcpy.Parameter(\n            displayName=\"Search distance\",\n            name=\"search_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        search_dist.value = '0.01'\n\n        min_points = arcpy.Parameter(\n            displayName=\"Minimum Points\",\n            name=\"min_points\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_points.value = '5'\n\n        params = [inputs, scaling, output, search_dist, min_points]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        scaling = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        search_dist = parameters[3].valueAsText\n        min_points = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.dbscan(inputs=inputs, scaling=scaling, output=output, search_dist=search_dist, min_points=min_points)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Decrement(object):\n    def __init__(self):\n        self.label = \"Decrement\"\n        self.description = \"Decreases the values of each grid cell in an input raster by 1.0 (see also InPlaceSubtract).\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.decrement(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DemVoidFilling(object):\n    def __init__(self):\n        self.label = \"Dem Void Filling\"\n        self.description = \"This tool can be used to fill the void areas of a DEM using another fill DEM data set.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        fill = arcpy.Parameter(\n            displayName=\"Input Fill DEM\",\n            name=\"fill\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output DEM\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        mean_plane_dist = arcpy.Parameter(\n            displayName=\"Mean-Plane Distance (in grid cells)\",\n            name=\"mean_plane_dist\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        mean_plane_dist.value = '20'\n\n        edge_treatment = arcpy.Parameter(\n            displayName=\"Void-Edge Treatment\",\n            name=\"edge_treatment\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        edge_treatment.filter.type = \"ValueList\"\n        edge_treatment.filter.list = ['use DEM', 'use fill', 'average']\n        edge_treatment.value = 'use DEM'\n\n        weight_value = arcpy.Parameter(\n            displayName=\"Interpolation Weight\",\n            name=\"weight_value\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        weight_value.value = '2.0'\n\n        params = [dem, fill, output, mean_plane_dist, edge_treatment, weight_value]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        fill = parameters[1].valueAsText\n        if fill is not None:\n            desc = arcpy.Describe(fill)\n            fill = desc.catalogPath\n        output = parameters[2].valueAsText\n        mean_plane_dist = parameters[3].valueAsText\n        edge_treatment = parameters[4].valueAsText\n        weight_value = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.dem_void_filling(dem=dem, fill=fill, output=output, mean_plane_dist=mean_plane_dist, edge_treatment=edge_treatment, weight_value=weight_value)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DepthInSink(object):\n    def __init__(self):\n        self.label = \"Depth In Sink\"\n        self.description = \"Measures the depth of sinks (depressions) in a DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        zero_background = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.depth_in_sink(dem=dem, output=output, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DepthToWater(object):\n    def __init__(self):\n        self.label = \"Depth To Water\"\n        self.description = \"This tool calculates cartographic depth-to-water (DTW) index.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams Vector\",\n            name=\"streams\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        streams.filter.list = [\"Polyline\"]\n\n        lakes = arcpy.Parameter(\n            displayName=\"Input Lakes Vector\",\n            name=\"lakes\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        lakes.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, streams, lakes, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        lakes = parameters[2].valueAsText\n        if lakes is not None:\n            desc = arcpy.Describe(lakes)\n            lakes = desc.catalogPath\n        output = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.depth_to_water(dem=dem, streams=streams, lakes=lakes, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DevFromMeanElev(object):\n    def __init__(self):\n        self.label = \"Dev From Mean Elev\"\n        self.description = \"Calculates deviation from mean elevation.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [dem, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.dev_from_mean_elev(dem=dem, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DiffFromMeanElev(object):\n    def __init__(self):\n        self.label = \"Diff From Mean Elev\"\n        self.description = \"Calculates difference from mean elevation (equivalent to a high-pass filter).\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [dem, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.diff_from_mean_elev(dem=dem, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DiffOfGaussianFilter(object):\n    def __init__(self):\n        self.label = \"Diff Of Gaussian Filter\"\n        self.description = \"Performs a Difference of Gaussian (DoG) filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        sigma1 = arcpy.Parameter(\n            displayName=\"Sigma 1 (pixels)\",\n            name=\"sigma1\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma1.value = '2.0'\n\n        sigma2 = arcpy.Parameter(\n            displayName=\"Sigma 2 (pixels)\",\n            name=\"sigma2\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma2.value = '4.0'\n\n        params = [i, output, sigma1, sigma2]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        sigma1 = parameters[2].valueAsText\n        sigma2 = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.diff_of_gaussian_filter(i=i, output=output, sigma1=sigma1, sigma2=sigma2)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Difference(object):\n    def __init__(self):\n        self.label = \"Difference\"\n        self.description = \"Outputs the features that occur in one of the two vector inputs but not both, i.e. no overlapping features.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        overlay = arcpy.Parameter(\n            displayName=\"Input Overlay Vector File\",\n            name=\"overlay\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, overlay, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        overlay = parameters[1].valueAsText\n        if overlay is not None:\n            desc = arcpy.Describe(overlay)\n            overlay = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.difference(i=i, overlay=overlay, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DifferenceCurvature(object):\n    def __init__(self):\n        self.label = \"Difference Curvature\"\n        self.description = \"This tool calculates difference curvature from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.difference_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DirectDecorrelationStretch(object):\n    def __init__(self):\n        self.label = \"Direct Decorrelation Stretch\"\n        self.description = \"Performs a direct decorrelation stretch enhancement on a colour-composite image of multispectral data.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Colour Composite Image File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        k = arcpy.Parameter(\n            displayName=\"Achromatic Factor (0-1)\",\n            name=\"k\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        k.value = '0.5'\n\n        clip = arcpy.Parameter(\n            displayName=\"Percent to clip the upper tail\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '1.0'\n\n        params = [i, output, k, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        k = parameters[2].valueAsText\n        clip = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.direct_decorrelation_stretch(i=i, output=output, k=k, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DirectionalRelief(object):\n    def __init__(self):\n        self.label = \"Directional Relief\"\n        self.description = \"Calculates relief for cells in an input DEM for a specified direction.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        azimuth = arcpy.Parameter(\n            displayName=\"Azimuth\",\n            name=\"azimuth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        azimuth.value = '0.0'\n\n        max_dist = arcpy.Parameter(\n            displayName=\"Maximum Search Distance\",\n            name=\"max_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, azimuth, max_dist]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        azimuth = parameters[2].valueAsText\n        max_dist = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.directional_relief(dem=dem, output=output, azimuth=azimuth, max_dist=max_dist)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Dissolve(object):\n    def __init__(self):\n        self.label = \"Dissolve\"\n        self.description = \"Removes the interior, or shared, boundaries within a vector polygon coverage.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Dissolve Field Attribute\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        snap = arcpy.Parameter(\n            displayName=\"Snap Tolerance\",\n            name=\"snap\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        snap.value = '0.0'\n\n        params = [i, field, output, snap]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        snap = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.dissolve(i=i, field=field, output=output, snap=snap)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DistanceToOutlet(object):\n    def __init__(self):\n        self.label = \"Distance To Outlet\"\n        self.description = \"Calculates the distance of stream grid cells to the channel network outlet cell.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.distance_to_outlet(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DiversityFilter(object):\n    def __init__(self):\n        self.label = \"Diversity Filter\"\n        self.description = \"Assigns each cell in the output grid the number of different values in a moving window centred on each grid cell in the input raster.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.diversity_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Divide(object):\n    def __init__(self):\n        self.label = \"Divide\"\n        self.description = \"Performs a division operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.divide(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DownslopeDistanceToStream(object):\n    def __init__(self):\n        self.label = \"Downslope Distance To Stream\"\n        self.description = \"Measures distance to the nearest downslope stream cell.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        dinf = arcpy.Parameter(\n            displayName=\"Use the D-infinity flow algorithm instead of D8?\",\n            name=\"dinf\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        dinf.value = 'False'\n\n        params = [dem, streams, output, dinf]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        dinf = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.downslope_distance_to_stream(dem=dem, streams=streams, output=output, dinf=dinf)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DownslopeFlowpathLength(object):\n    def __init__(self):\n        self.label = \"Downslope Flowpath Length\"\n        self.description = \"Calculates the downslope flowpath length from each cell to basin outlet.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        watersheds = arcpy.Parameter(\n            displayName=\"Input Watersheds File (optional)\",\n            name=\"watersheds\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        weights = arcpy.Parameter(\n            displayName=\"Input Weights File (optional)\",\n            name=\"weights\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, watersheds, weights, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        watersheds = parameters[1].valueAsText\n        if watersheds is not None:\n            desc = arcpy.Describe(watersheds)\n            watersheds = desc.catalogPath\n        weights = parameters[2].valueAsText\n        if weights is not None:\n            desc = arcpy.Describe(weights)\n            weights = desc.catalogPath\n        output = parameters[3].valueAsText\n        esri_pntr = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.downslope_flowpath_length(d8_pntr=d8_pntr, watersheds=watersheds, weights=weights, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DownslopeIndex(object):\n    def __init__(self):\n        self.label = \"Downslope Index\"\n        self.description = \"Calculates the Hjerdt et al. (2004) downslope index.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        drop = arcpy.Parameter(\n            displayName=\"Verical Drop\",\n            name=\"drop\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        drop.value = '2.0'\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['tangent', 'degrees', 'radians', 'distance']\n        out_type.value = 'tangent'\n\n        params = [dem, output, drop, out_type]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        drop = parameters[2].valueAsText\n        out_type = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.downslope_index(dem=dem, output=output, drop=drop, out_type=out_type)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EdgeContamination(object):\n    def __init__(self):\n        self.label = \"Edge Contamination\"\n        self.description = \"Identifies grid cells within an input DEM that may be impacted by edge contamination for hydrological applications.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        flow_type = arcpy.Parameter(\n            displayName=\"Flow Type\",\n            name=\"flow_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        flow_type.filter.type = \"ValueList\"\n        flow_type.filter.list = ['d8', 'mfd', 'dinf']\n        flow_type.value = 'mfd'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        params = [dem, output, flow_type, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        flow_type = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.edge_contamination(dem=dem, output=output, flow_type=flow_type, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EdgeDensity(object):\n    def __init__(self):\n        self.label = \"Edge Density\"\n        self.description = \"Calculates the density of edges, or breaks-in-slope within DEMs.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Size\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '11'\n\n        norm_diff = arcpy.Parameter(\n            displayName=\"Normal Difference Threshold\",\n            name=\"norm_diff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        norm_diff.value = '5.0'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, filter, norm_diff, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        norm_diff = parameters[3].valueAsText\n        zfactor = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.edge_density(dem=dem, output=output, filter=filter, norm_diff=norm_diff, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EdgePreservingMeanFilter(object):\n    def __init__(self):\n        self.label = \"Edge Preserving Mean Filter\"\n        self.description = \"Performs a simple edge-preserving mean filter on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Size\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '11'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Value Difference Threshold\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, output, filter, threshold]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        threshold = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.edge_preserving_mean_filter(i=i, output=output, filter=filter, threshold=threshold)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EdgeProportion(object):\n    def __init__(self):\n        self.label = \"Edge Proportion\"\n        self.description = \"Calculate the proportion of cells in a raster polygon that are edge cells.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        output_text = arcpy.Parameter(\n            displayName=\"Output a text report?\",\n            name=\"output_text\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, output_text]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        output_text = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.edge_proportion(i=i, output=output, output_text=output_text)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ElevAbovePit(object):\n    def __init__(self):\n        self.label = \"Elev Above Pit\"\n        self.description = \"Calculate the elevation of each grid cell above the nearest downstream pit cell or grid edge cell.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.elev_above_pit(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ElevPercentile(object):\n    def __init__(self):\n        self.label = \"Elev Percentile\"\n        self.description = \"Calculates the elevation percentile raster from a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        sig_digits = arcpy.Parameter(\n            displayName=\"Number of Significant Digits\",\n            name=\"sig_digits\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sig_digits.value = '2'\n\n        params = [dem, output, filterx, filtery, sig_digits]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        sig_digits = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.elev_percentile(dem=dem, output=output, filterx=filterx, filtery=filtery, sig_digits=sig_digits)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ElevRelativeToMinMax(object):\n    def __init__(self):\n        self.label = \"Elev Relative To Min Max\"\n        self.description = \"Calculates the elevation of a location relative to the minimum and maximum elevations in a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.elev_relative_to_min_max(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ElevRelativeToWatershedMinMax(object):\n    def __init__(self):\n        self.label = \"Elev Relative To Watershed Min Max\"\n        self.description = \"Calculates the elevation of a location relative to the minimum and maximum elevations in a watershed.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        watersheds = arcpy.Parameter(\n            displayName=\"Input Watersheds File\",\n            name=\"watersheds\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, watersheds, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        watersheds = parameters[1].valueAsText\n        if watersheds is not None:\n            desc = arcpy.Describe(watersheds)\n            watersheds = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.elev_relative_to_watershed_min_max(dem=dem, watersheds=watersheds, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ElevationAboveStream(object):\n    def __init__(self):\n        self.label = \"Elevation Above Stream\"\n        self.description = \"Calculates the elevation of cells above the nearest downslope stream cell.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, streams, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.elevation_above_stream(dem=dem, streams=streams, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ElevationAboveStreamEuclidean(object):\n    def __init__(self):\n        self.label = \"Elevation Above Stream Euclidean\"\n        self.description = \"Calculates the elevation of cells above the nearest (Euclidean distance) stream cell.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, streams, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.elevation_above_stream_euclidean(dem=dem, streams=streams, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EliminateCoincidentPoints(object):\n    def __init__(self):\n        self.label = \"Eliminate Coincident Points\"\n        self.description = \"Removes any coincident, or nearly coincident, points from a vector points file.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Points File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        tolerance = arcpy.Parameter(\n            displayName=\"Distance Tolerance\",\n            name=\"tolerance\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, output, tolerance]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        tolerance = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.eliminate_coincident_points(i=i, output=output, tolerance=tolerance)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ElongationRatio(object):\n    def __init__(self):\n        self.label = \"Elongation Ratio\"\n        self.description = \"Calculates the elongation ratio for vector polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.elongation_ratio(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EmbankmentMapping(object):\n    def __init__(self):\n        self.label = \"Embankment Mapping\"\n        self.description = \"Maps and/or removes road embankments from an input fine-resolution DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        road_vec = arcpy.Parameter(\n            displayName=\"Input Vector Transportation Line File\",\n            name=\"road_vec\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        road_vec.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        search_dist = arcpy.Parameter(\n            displayName=\"Search Distance (in map units)\",\n            name=\"search_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        search_dist.value = '2.5'\n\n        min_road_width = arcpy.Parameter(\n            displayName=\"Minimum Road Width (in map units)\",\n            name=\"min_road_width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        min_road_width.value = '6.0'\n\n        typical_width = arcpy.Parameter(\n            displayName=\"Typical Embankment Width (in map units)\",\n            name=\"typical_width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        typical_width.value = '30.0'\n\n        max_height = arcpy.Parameter(\n            displayName=\"Typical Embankment Max Height (in map units)\",\n            name=\"max_height\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        max_height.value = '2.0'\n\n        max_width = arcpy.Parameter(\n            displayName=\"Embankment Max Width (in map units)\",\n            name=\"max_width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        max_width.value = '60.0'\n\n        max_increment = arcpy.Parameter(\n            displayName=\"Max Upwards Increment (in elevation units)\",\n            name=\"max_increment\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        max_increment.value = '0.05'\n\n        spillout_slope = arcpy.Parameter(\n            displayName=\"Spillout Slope (in map units)\",\n            name=\"spillout_slope\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        spillout_slope.value = '4.0'\n\n        remove_embankments = arcpy.Parameter(\n            displayName=\"Remove mapped embankments?\",\n            name=\"remove_embankments\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        remove_embankments.value = 'False'\n\n        params = [dem, road_vec, output, search_dist, min_road_width, typical_width, max_height, max_width, max_increment, spillout_slope, remove_embankments]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        road_vec = parameters[1].valueAsText\n        if road_vec is not None:\n            desc = arcpy.Describe(road_vec)\n            road_vec = desc.catalogPath\n        output = parameters[2].valueAsText\n        search_dist = parameters[3].valueAsText\n        min_road_width = parameters[4].valueAsText\n        typical_width = parameters[5].valueAsText\n        max_height = parameters[6].valueAsText\n        max_width = parameters[7].valueAsText\n        max_increment = parameters[8].valueAsText\n        spillout_slope = parameters[9].valueAsText\n        remove_embankments = parameters[10].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.embankment_mapping(dem=dem, road_vec=road_vec, output=output, search_dist=search_dist, min_road_width=min_road_width, typical_width=typical_width, max_height=max_height, max_width=max_width, max_increment=max_increment, spillout_slope=spillout_slope, remove_embankments=remove_embankments)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EmbossFilter(object):\n    def __init__(self):\n        self.label = \"Emboss Filter\"\n        self.description = \"Performs an emboss filter on an image, similar to a hillshade operation.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        direction = arcpy.Parameter(\n            displayName=\"Direction\",\n            name=\"direction\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        direction.filter.type = \"ValueList\"\n        direction.filter.list = ['n', 's', 'e', 'w', 'ne', 'se', 'nw', 'sw']\n        direction.value = 'n'\n\n        clip = arcpy.Parameter(\n            displayName=\"Percent to clip the distribution tails\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '0.0'\n\n        params = [i, output, direction, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        direction = parameters[2].valueAsText\n        clip = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.emboss_filter(i=i, output=output, direction=direction, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EqualTo(object):\n    def __init__(self):\n        self.label = \"Equal To\"\n        self.description = \"Performs a equal-to comparison operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.equal_to(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Erase(object):\n    def __init__(self):\n        self.label = \"Erase\"\n        self.description = \"Removes all the features, or parts of features, that overlap with the features of the erase vector polygon.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        erase = arcpy.Parameter(\n            displayName=\"Input Erase Polygon Vector File\",\n            name=\"erase\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        erase.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, erase, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        erase = parameters[1].valueAsText\n        if erase is not None:\n            desc = arcpy.Describe(erase)\n            erase = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.erase(i=i, erase=erase, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ErasePolygonFromLidar(object):\n    def __init__(self):\n        self.label = \"Erase Polygon From Lidar\"\n        self.description = \"Erases (cuts out) a vector polygon or polygons from a LiDAR point cloud.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        polygons = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"polygons\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        polygons.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, polygons, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        polygons = parameters[1].valueAsText\n        if polygons is not None:\n            desc = arcpy.Describe(polygons)\n            polygons = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.erase_polygon_from_lidar(i=i, polygons=polygons, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ErasePolygonFromRaster(object):\n    def __init__(self):\n        self.label = \"Erase Polygon From Raster\"\n        self.description = \"Erases (cuts out) a vector polygon from a raster.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        polygons = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"polygons\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        polygons.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, polygons, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        polygons = parameters[1].valueAsText\n        if polygons is not None:\n            desc = arcpy.Describe(polygons)\n            polygons = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.erase_polygon_from_raster(i=i, polygons=polygons, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EuclideanAllocation(object):\n    def __init__(self):\n        self.label = \"Euclidean Allocation\"\n        self.description = \"Assigns grid cells in the output raster the value of the nearest target cell in the input image, measured by the Shih and Wu (2004) Euclidean distance transform.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.euclidean_allocation(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EuclideanDistance(object):\n    def __init__(self):\n        self.label = \"Euclidean Distance\"\n        self.description = \"Calculates the Shih and Wu (2004) Euclidean distance transform.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.euclidean_distance(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EvaluateTrainingSites(object):\n    def __init__(self):\n        self.label = \"Evaluate Training Sites\"\n        self.description = \"This tool can be used to inspect the overlap in spectral signatures of training sites for various classes.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Band Images\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        polys = arcpy.Parameter(\n            displayName=\"Input Training Polygons\",\n            name=\"polys\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        polys.filter.list = [\"Polygon\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Class Name Field\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [polys.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File (*.html)\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [inputs, polys, field, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        polys = parameters[1].valueAsText\n        if polys is not None:\n            desc = arcpy.Describe(polys)\n            polys = desc.catalogPath\n        field = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.evaluate_training_sites(inputs=inputs, polys=polys, field=field, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Exp(object):\n    def __init__(self):\n        self.label = \"Exp\"\n        self.description = \"Returns the exponential (base e) of values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.exp(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Exp2(object):\n    def __init__(self):\n        self.label = \"Exp2\"\n        self.description = \"Returns the exponential (base 2) of values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.exp2(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ExportTableToCsv(object):\n    def __init__(self):\n        self.label = \"Export Table To Csv\"\n        self.description = \"Exports an attribute table to a CSV text file.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"csv\"]\n\n        headers = arcpy.Parameter(\n            displayName=\"Export field names as file header?\",\n            name=\"headers\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        headers.value = 'True'\n\n        params = [i, output, headers]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        headers = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.export_table_to_csv(i=i, output=output, headers=headers)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ExposureTowardsWindFlux(object):\n    def __init__(self):\n        self.label = \"Exposure Towards Wind Flux\"\n        self.description = \"Evaluates hydrologic connectivity within a DEM\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        azimuth = arcpy.Parameter(\n            displayName=\"Wind Azimuth (in degrees)\",\n            name=\"azimuth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        max_dist = arcpy.Parameter(\n            displayName=\"Maximum Search Distance\",\n            name=\"max_dist\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        params = [dem, output, azimuth, max_dist, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        azimuth = parameters[2].valueAsText\n        max_dist = parameters[3].valueAsText\n        zfactor = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.exposure_towards_wind_flux(dem=dem, output=output, azimuth=azimuth, max_dist=max_dist, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ExtendVectorLines(object):\n    def __init__(self):\n        self.label = \"Extend Vector Lines\"\n        self.description = \"Extends vector lines by a specified distance.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Lines File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        dist = arcpy.Parameter(\n            displayName=\"Extend Distance\",\n            name=\"dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        extend = arcpy.Parameter(\n            displayName=\"Extend Direction\",\n            name=\"extend\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        extend.filter.type = \"ValueList\"\n        extend.filter.list = ['both ends', 'line start', 'line end']\n        extend.value = 'both ends'\n\n        params = [i, output, dist, extend]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        dist = parameters[2].valueAsText\n        extend = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.extend_vector_lines(i=i, output=output, dist=dist, extend=extend)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ExtractNodes(object):\n    def __init__(self):\n        self.label = \"Extract Nodes\"\n        self.description = \"Converts vector lines or polygons into vertex points.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Points File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.extract_nodes(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ExtractRasterValuesAtPoints(object):\n    def __init__(self):\n        self.label = \"Extract Raster Values At Points\"\n        self.description = \"Extracts the values of raster(s) at vector point locations.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        points = arcpy.Parameter(\n            displayName=\"Input Points File\",\n            name=\"points\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        points.filter.list = [\"Point\"]\n\n        out_text = arcpy.Parameter(\n            displayName=\"Output text?\",\n            name=\"out_text\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_text.value = 'False'\n\n        params = [inputs, points, out_text]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        points = parameters[1].valueAsText\n        if points is not None:\n            desc = arcpy.Describe(points)\n            points = desc.catalogPath\n        out_text = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.extract_raster_values_at_points(inputs=inputs, points=points, out_text=out_text)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ExtractStreams(object):\n    def __init__(self):\n        self.label = \"Extract Streams\"\n        self.description = \"Extracts stream grid cells from a flow accumulation raster.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        flow_accum = arcpy.Parameter(\n            displayName=\"Input D8 Flow Accumulation File\",\n            name=\"flow_accum\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        threshold = arcpy.Parameter(\n            displayName=\"Channelization Threshold\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [flow_accum, output, threshold, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        flow_accum = parameters[0].valueAsText\n        if flow_accum is not None:\n            desc = arcpy.Describe(flow_accum)\n            flow_accum = desc.catalogPath\n        output = parameters[1].valueAsText\n        threshold = parameters[2].valueAsText\n        zero_background = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.extract_streams(flow_accum=flow_accum, output=output, threshold=threshold, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ExtractValleys(object):\n    def __init__(self):\n        self.label = \"Extract Valleys\"\n        self.description = \"Identifies potential valley bottom grid cells based on local topolography alone.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        variant = arcpy.Parameter(\n            displayName=\"Variant\",\n            name=\"variant\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        variant.filter.type = \"ValueList\"\n        variant.filter.list = ['LQ', 'JandR', 'PandD']\n        variant.value = 'LQ'\n\n        line_thin = arcpy.Parameter(\n            displayName=\"Perform line-thinning?\",\n            name=\"line_thin\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        line_thin.value = 'True'\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Size (Only For Lower Quartile)\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '5'\n\n        params = [dem, output, variant, line_thin, filter]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        variant = parameters[2].valueAsText\n        line_thin = parameters[3].valueAsText\n        filter = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.extract_valleys(dem=dem, output=output, variant=variant, line_thin=line_thin, filter=filter)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Fd8FlowAccumulation(object):\n    def __init__(self):\n        self.label = \"Fd8 Flow Accumulation\"\n        self.description = \"Calculates an FD8 flow accumulation raster from an input DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['cells', 'specific contributing area', 'catchment area']\n        out_type.value = 'specific contributing area'\n\n        exponent = arcpy.Parameter(\n            displayName=\"Exponent Parameter\",\n            name=\"exponent\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        exponent.value = '1.1'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Convergence Threshold (grid cells; blank for none)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip the upper tail by 1%?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, out_type, exponent, threshold, log, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_type = parameters[2].valueAsText\n        exponent = parameters[3].valueAsText\n        threshold = parameters[4].valueAsText\n        log = parameters[5].valueAsText\n        clip = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fd8_flow_accumulation(dem=dem, output=output, out_type=out_type, exponent=exponent, threshold=threshold, log=log, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Fd8Pointer(object):\n    def __init__(self):\n        self.label = \"Fd8 Pointer\"\n        self.description = \"Calculates an FD8 flow pointer raster from an input DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fd8_pointer(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FarthestChannelHead(object):\n    def __init__(self):\n        self.label = \"Farthest Channel Head\"\n        self.description = \"Calculates the distance to the furthest upstream channel head for each stream cell.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.farthest_channel_head(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FastAlmostGaussianFilter(object):\n    def __init__(self):\n        self.label = \"Fast Almost Gaussian Filter\"\n        self.description = \"Performs a fast approximate Gaussian filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        sigma = arcpy.Parameter(\n            displayName=\"Standard Deviation (pixels)\",\n            name=\"sigma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        sigma.value = '1.8'\n\n        params = [i, output, sigma]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        sigma = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fast_almost_gaussian_filter(i=i, output=output, sigma=sigma)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FeaturePreservingSmoothing(object):\n    def __init__(self):\n        self.label = \"Feature Preserving Smoothing\"\n        self.description = \"Reduces short-scale variation in an input DEM using a modified Sun et al. (2007) algorithm.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Size\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '11'\n\n        norm_diff = arcpy.Parameter(\n            displayName=\"Normal Difference Threshold\",\n            name=\"norm_diff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        norm_diff.value = '15.0'\n\n        num_iter = arcpy.Parameter(\n            displayName=\"Iterations\",\n            name=\"num_iter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_iter.value = '3'\n\n        max_diff = arcpy.Parameter(\n            displayName=\"Maximum Elevation Change\",\n            name=\"max_diff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_diff.value = '0.5'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, filter, norm_diff, num_iter, max_diff, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        norm_diff = parameters[3].valueAsText\n        num_iter = parameters[4].valueAsText\n        max_diff = parameters[5].valueAsText\n        zfactor = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.feature_preserving_smoothing(dem=dem, output=output, filter=filter, norm_diff=norm_diff, num_iter=num_iter, max_diff=max_diff, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FetchAnalysis(object):\n    def __init__(self):\n        self.label = \"Fetch Analysis\"\n        self.description = \"Performs an analysis of fetch or upwind distance to an obstacle.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        azimuth = arcpy.Parameter(\n            displayName=\"Azimuth (degrees)\",\n            name=\"azimuth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        azimuth.value = '0.0'\n\n        hgt_inc = arcpy.Parameter(\n            displayName=\"Height Increment Value\",\n            name=\"hgt_inc\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        hgt_inc.value = '0.05'\n\n        params = [dem, output, azimuth, hgt_inc]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        azimuth = parameters[2].valueAsText\n        hgt_inc = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fetch_analysis(dem=dem, output=output, azimuth=azimuth, hgt_inc=hgt_inc)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FillBurn(object):\n    def __init__(self):\n        self.label = \"Fill Burn\"\n        self.description = \"Burns streams into a DEM using the FillBurn (Saunders, 1999) method.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Vector Streams File\",\n            name=\"streams\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        streams.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, streams, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fill_burn(dem=dem, streams=streams, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FillDepressions(object):\n    def __init__(self):\n        self.label = \"Fill Depressions\"\n        self.description = \"Fills all of the depressions in a DEM. Depression breaching should be preferred in most cases.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        fix_flats = arcpy.Parameter(\n            displayName=\"Fix flat areas?\",\n            name=\"fix_flats\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        fix_flats.value = 'True'\n\n        flat_increment = arcpy.Parameter(\n            displayName=\"Flat increment value (z units)\",\n            name=\"flat_increment\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_depth = arcpy.Parameter(\n            displayName=\"Maximum depth (z units)\",\n            name=\"max_depth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, fix_flats, flat_increment, max_depth]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        fix_flats = parameters[2].valueAsText\n        flat_increment = parameters[3].valueAsText\n        max_depth = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fill_depressions(dem=dem, output=output, fix_flats=fix_flats, flat_increment=flat_increment, max_depth=max_depth)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FillDepressionsPlanchonAndDarboux(object):\n    def __init__(self):\n        self.label = \"Fill Depressions Planchon And Darboux\"\n        self.description = \"Fills all of the depressions in a DEM using the Planchon and Darboux (2002) method.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        fix_flats = arcpy.Parameter(\n            displayName=\"Fix flat areas?\",\n            name=\"fix_flats\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        fix_flats.value = 'True'\n\n        flat_increment = arcpy.Parameter(\n            displayName=\"Flat increment value (z units)\",\n            name=\"flat_increment\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, fix_flats, flat_increment]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        fix_flats = parameters[2].valueAsText\n        flat_increment = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fill_depressions_planchon_and_darboux(dem=dem, output=output, fix_flats=fix_flats, flat_increment=flat_increment)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FillDepressionsWangAndLiu(object):\n    def __init__(self):\n        self.label = \"Fill Depressions Wang And Liu\"\n        self.description = \"Fills all of the depressions in a DEM using the Wang and Liu (2006) method. Depression breaching should be preferred in most cases.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        fix_flats = arcpy.Parameter(\n            displayName=\"Fix flat areas?\",\n            name=\"fix_flats\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        fix_flats.value = 'True'\n\n        flat_increment = arcpy.Parameter(\n            displayName=\"Flat increment value (z units)\",\n            name=\"flat_increment\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, fix_flats, flat_increment]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        fix_flats = parameters[2].valueAsText\n        flat_increment = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fill_depressions_wang_and_liu(dem=dem, output=output, fix_flats=fix_flats, flat_increment=flat_increment)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FillMissingData(object):\n    def __init__(self):\n        self.label = \"Fill Missing Data\"\n        self.description = \"Fills NoData holes in a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Dimension\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        filter.value = '11'\n\n        weight = arcpy.Parameter(\n            displayName=\"IDW Weight (Exponent) Value\",\n            name=\"weight\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        weight.value = '2.0'\n\n        no_edges = arcpy.Parameter(\n            displayName=\"Exclude edge-of-raster-connected NoData cells?\",\n            name=\"no_edges\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        no_edges.value = 'True'\n\n        params = [i, output, filter, weight, no_edges]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        weight = parameters[3].valueAsText\n        no_edges = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fill_missing_data(i=i, output=output, filter=filter, weight=weight, no_edges=no_edges)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FillSingleCellPits(object):\n    def __init__(self):\n        self.label = \"Fill Single Cell Pits\"\n        self.description = \"Raises pit cells to the elevation of their lowest neighbour.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fill_single_cell_pits(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FilterLidar(object):\n    def __init__(self):\n        self.label = \"Filter Lidar\"\n        self.description = \"Filters points within a LiDAR point cloud based on point properties.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR Points\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        statement = arcpy.Parameter(\n            displayName=\"Statement:\",\n            name=\"statement\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        params = [i, output, statement]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        statement = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.filter_lidar(i=i, output=output, statement=statement)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FilterLidarClasses(object):\n    def __init__(self):\n        self.label = \"Filter Lidar Classes\"\n        self.description = \"Removes points in a LAS file with certain specified class values.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        exclude_cls = arcpy.Parameter(\n            displayName=\"Exclusion Classes (0-18, based on LAS spec; e.g. 7,18)\",\n            name=\"exclude_cls\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, exclude_cls]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        exclude_cls = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.filter_lidar_classes(i=i, output=output, exclude_cls=exclude_cls)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FilterLidarScanAngles(object):\n    def __init__(self):\n        self.label = \"Filter Lidar Scan Angles\"\n        self.description = \"Removes points in a LAS file with scan angles greater than a threshold.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        threshold = arcpy.Parameter(\n            displayName=\"Threshold (degrees)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, output, threshold]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        threshold = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.filter_lidar_scan_angles(i=i, output=output, threshold=threshold)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FilterRasterFeaturesByArea(object):\n    def __init__(self):\n        self.label = \"Filter Raster Features By Area\"\n        self.description = \"Removes small-area features from a raster.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        threshold = arcpy.Parameter(\n            displayName=\"Area Threshold (grid cells)\",\n            name=\"threshold\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        background = arcpy.Parameter(\n            displayName=\"Background Value\",\n            name=\"background\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        background.filter.type = \"ValueList\"\n        background.filter.list = ['zero', 'nodata']\n        background.value = 'zero'\n\n        params = [i, output, threshold, background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        threshold = parameters[2].valueAsText\n        background = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.filter_raster_features_by_area(i=i, output=output, threshold=threshold, background=background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FindFlightlineEdgePoints(object):\n    def __init__(self):\n        self.label = \"Find Flightline Edge Points\"\n        self.description = \"Identifies points along a flightline's edge in a LAS file.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.find_flightline_edge_points(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FindLowestOrHighestPoints(object):\n    def __init__(self):\n        self.label = \"Find Lowest Or Highest Points\"\n        self.description = \"Locates the lowest and/or highest valued cells in a raster.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Points File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['lowest', 'highest', 'both']\n        out_type.value = 'lowest'\n\n        params = [i, output, out_type]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_type = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.find_lowest_or_highest_points(i=i, output=output, out_type=out_type)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FindMainStem(object):\n    def __init__(self):\n        self.label = \"Find Main Stem\"\n        self.description = \"Finds the main stem, based on stream lengths, of each stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.find_main_stem(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FindNoFlowCells(object):\n    def __init__(self):\n        self.label = \"Find No Flow Cells\"\n        self.description = \"Finds grid cells with no downslope neighbours.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.find_no_flow_cells(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FindParallelFlow(object):\n    def __init__(self):\n        self.label = \"Find Parallel Flow\"\n        self.description = \"Finds areas of parallel flow in D8 flow direction rasters.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [d8_pntr, streams, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.find_parallel_flow(d8_pntr=d8_pntr, streams=streams, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FindPatchOrClassEdgeCells(object):\n    def __init__(self):\n        self.label = \"Find Patch Or Class Edge Cells\"\n        self.description = \"Finds all cells located on the edge of patch or class features.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.find_patch_or_class_edge_cells(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FindRidges(object):\n    def __init__(self):\n        self.label = \"Find Ridges\"\n        self.description = \"Identifies potential ridge and peak grid cells.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        line_thin = arcpy.Parameter(\n            displayName=\"Perform line-thinning?\",\n            name=\"line_thin\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        line_thin.value = 'True'\n\n        params = [dem, output, line_thin]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        line_thin = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.find_ridges(dem=dem, output=output, line_thin=line_thin)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FixDanglingArcs(object):\n    def __init__(self):\n        self.label = \"Fix Dangling Arcs\"\n        self.description = \"This tool fixes undershot and overshot arcs, two common topological errors, in an input vector lines file.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Lines\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Lines\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        dist = arcpy.Parameter(\n            displayName=\"Snap Distance\",\n            name=\"dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        params = [i, output, dist]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        dist = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fix_dangling_arcs(i=i, output=output, dist=dist)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FlattenLakes(object):\n    def __init__(self):\n        self.label = \"Flatten Lakes\"\n        self.description = \"Flattens lake polygons in a raster DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        lakes = arcpy.Parameter(\n            displayName=\"Input Lakes Vector Polygon File\",\n            name=\"lakes\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        lakes.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, lakes, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        lakes = parameters[1].valueAsText\n        if lakes is not None:\n            desc = arcpy.Describe(lakes)\n            lakes = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.flatten_lakes(dem=dem, lakes=lakes, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FlightlineOverlap(object):\n    def __init__(self):\n        self.label = \"Flightline Overlap\"\n        self.description = \"Reads a LiDAR (LAS) point file and outputs a raster containing the number of overlapping flight-lines in each grid cell.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        params = [i, output, resolution]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        resolution = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.flightline_overlap(i=i, output=output, resolution=resolution)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FlipImage(object):\n    def __init__(self):\n        self.label = \"Flip Image\"\n        self.description = \"Reflects an image in the vertical or horizontal axis.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        direction = arcpy.Parameter(\n            displayName=\"Direction\",\n            name=\"direction\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        direction.filter.type = \"ValueList\"\n        direction.filter.list = ['vertical', 'horizontal', 'both']\n        direction.value = 'vertical'\n\n        params = [i, output, direction]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        direction = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.flip_image(i=i, output=output, direction=direction)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FloodOrder(object):\n    def __init__(self):\n        self.label = \"Flood Order\"\n        self.description = \"Assigns each DEM grid cell its order in the sequence of inundations that are encountered during a search starting from the edges, moving inward at increasing elevations.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.flood_order(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Floor(object):\n    def __init__(self):\n        self.label = \"Floor\"\n        self.description = \"Returns the largest (closest to positive infinity) value that is less than or equal to the values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.floor(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FlowAccumulationFullWorkflow(object):\n    def __init__(self):\n        self.label = \"Flow Accumulation Full Workflow\"\n        self.description = \"Resolves all of the depressions in a DEM, outputting a breached DEM, an aspect-aligned non-divergent flow pointer, and a flow accumulation raster.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_dem = arcpy.Parameter(\n            displayName=\"Output DEM File\",\n            name=\"out_dem\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_dem.filter.list = [\"tif\"]\n\n        out_pntr = arcpy.Parameter(\n            displayName=\"Output Flow Pointer File\",\n            name=\"out_pntr\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_pntr.filter.list = [\"tif\"]\n\n        out_accum = arcpy.Parameter(\n            displayName=\"Output Flow Accumulation File\",\n            name=\"out_accum\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_accum.filter.list = [\"tif\"]\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['Cells', 'Specific Contributing Area', 'Catchment Area']\n        out_type.value = 'Specific Contributing Area'\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip the upper tail by 1%?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [dem, out_dem, out_pntr, out_accum, out_type, log, clip, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        out_dem = parameters[1].valueAsText\n        out_pntr = parameters[2].valueAsText\n        out_accum = parameters[3].valueAsText\n        out_type = parameters[4].valueAsText\n        log = parameters[5].valueAsText\n        clip = parameters[6].valueAsText\n        esri_pntr = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.flow_accumulation_full_workflow(dem=dem, out_dem=out_dem, out_pntr=out_pntr, out_accum=out_accum, out_type=out_type, log=log, clip=clip, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FlowLengthDiff(object):\n    def __init__(self):\n        self.label = \"Flow Length Diff\"\n        self.description = \"Calculates the local maximum absolute difference in downslope flowpath length, useful in mapping drainage divides and ridges.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        output = parameters[1].valueAsText\n        esri_pntr = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.flow_length_diff(d8_pntr=d8_pntr, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass GammaCorrection(object):\n    def __init__(self):\n        self.label = \"Gamma Correction\"\n        self.description = \"Performs a gamma correction on an input images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        gamma = arcpy.Parameter(\n            displayName=\"Gamma Value\",\n            name=\"gamma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        gamma.value = '0.5'\n\n        params = [i, output, gamma]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        gamma = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.gamma_correction(i=i, output=output, gamma=gamma)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass GaussianContrastStretch(object):\n    def __init__(self):\n        self.label = \"Gaussian Contrast Stretch\"\n        self.description = \"Performs a Gaussian contrast stretch on input images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        num_tones = arcpy.Parameter(\n            displayName=\"Number of Tones\",\n            name=\"num_tones\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_tones.value = '256'\n\n        params = [i, output, num_tones]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        num_tones = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.gaussian_contrast_stretch(i=i, output=output, num_tones=num_tones)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass GaussianCurvature(object):\n    def __init__(self):\n        self.label = \"Gaussian Curvature\"\n        self.description = \"Calculates a mean curvature raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.gaussian_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass GaussianFilter(object):\n    def __init__(self):\n        self.label = \"Gaussian Filter\"\n        self.description = \"Performs a Gaussian filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        sigma = arcpy.Parameter(\n            displayName=\"Standard Deviation (pixels)\",\n            name=\"sigma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        sigma.value = '0.75'\n\n        params = [i, output, sigma]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        sigma = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.gaussian_filter(i=i, output=output, sigma=sigma)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass GaussianScaleSpace(object):\n    def __init__(self):\n        self.label = \"Gaussian Scale Space\"\n        self.description = \"Uses the fast Gaussian approximation algorithm to produce scaled land-surface parameter measurements from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        points = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"points\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        points.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Land-surface Parameter Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        output_zscore = arcpy.Parameter(\n            displayName=\"Output z-Score Raster File\",\n            name=\"output_zscore\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output_zscore.filter.list = [\"tif\"]\n\n        output_scale = arcpy.Parameter(\n            displayName=\"Output Scale Raster File\",\n            name=\"output_scale\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output_scale.filter.list = [\"tif\"]\n\n        sigma = arcpy.Parameter(\n            displayName=\"Starting Scale\",\n            name=\"sigma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        sigma.value = '0.5'\n\n        step = arcpy.Parameter(\n            displayName=\"Step Size\",\n            name=\"step\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step.value = '0.5'\n\n        num_steps = arcpy.Parameter(\n            displayName=\"Number of Steps\",\n            name=\"num_steps\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_steps.value = '10'\n\n        lsp = arcpy.Parameter(\n            displayName=\"Land-surface Parameter to Calculate\",\n            name=\"lsp\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        lsp.filter.type = \"ValueList\"\n        lsp.filter.list = ['AnisotropyLTP', 'Aspect', 'DiffMeanElev', 'Eastness', 'Elevation', 'Hillshade', 'MeanCurvature', 'Northness', 'PlanCurvature', 'ProfileCurvature', 'Ruggedness', 'Slope', 'TanCurvature', 'TotalCurvature']\n        lsp.value = 'Slope'\n\n        z_factor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"z_factor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, points, output, output_zscore, output_scale, sigma, step, num_steps, lsp, z_factor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        points = parameters[1].valueAsText\n        if points is not None:\n            desc = arcpy.Describe(points)\n            points = desc.catalogPath\n        output = parameters[2].valueAsText\n        output_zscore = parameters[3].valueAsText\n        output_scale = parameters[4].valueAsText\n        sigma = parameters[5].valueAsText\n        step = parameters[6].valueAsText\n        num_steps = parameters[7].valueAsText\n        lsp = parameters[8].valueAsText\n        z_factor = parameters[9].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.gaussian_scale_space(dem=dem, points=points, output=output, output_zscore=output_zscore, output_scale=output_scale, sigma=sigma, step=step, num_steps=num_steps, lsp=lsp, z_factor=z_factor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass GeneralizeClassifiedRaster(object):\n    def __init__(self):\n        self.label = \"Generalize Classified Raster\"\n        self.description = \"Generalizes a raster containing class or object features by removing small features.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster Image\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        min_size = arcpy.Parameter(\n            displayName=\"Min. Feature Size (in grid cells)\",\n            name=\"min_size\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_size.value = '4'\n\n        method = arcpy.Parameter(\n            displayName=\"Method\",\n            name=\"method\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        method.filter.type = \"ValueList\"\n        method.filter.list = ['longest', 'largest', 'nearest']\n        method.value = 'longest'\n\n        params = [i, output, min_size, method]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        min_size = parameters[2].valueAsText\n        method = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.generalize_classified_raster(i=i, output=output, min_size=min_size, method=method)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass GeneralizeWithSimilarity(object):\n    def __init__(self):\n        self.label = \"Generalize With Similarity\"\n        self.description = \"Generalizes a raster containing class or object features by removing small features using similarity criteria of neighbouring features.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster Image\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        similarity = arcpy.Parameter(\n            displayName=\"Input Similarity Images\",\n            name=\"similarity\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        similarity.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        min_size = arcpy.Parameter(\n            displayName=\"Min. Feature Size (in grid cells)\",\n            name=\"min_size\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_size.value = '4'\n\n        params = [i, similarity, output, min_size]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        similarity = parameters[1].valueAsText\n        if similarity is not None:\n            items = similarity.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            similarity = \";\".join(items_path)\n        output = parameters[2].valueAsText\n        min_size = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.generalize_with_similarity(i=i, similarity=similarity, output=output, min_size=min_size)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass GeneratingFunction(object):\n    def __init__(self):\n        self.label = \"Generating Function\"\n        self.description = \"This tool calculates generating function from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.generating_function(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Geomorphons(object):\n    def __init__(self):\n        self.label = \"Geomorphons\"\n        self.description = \"Computes geomorphon patterns.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM file.\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output file.\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        search = arcpy.Parameter(\n            displayName=\"Search distance (cells).\",\n            name=\"search\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        search.value = '50'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Flatness threshold (degrees).\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        threshold.value = '0.0'\n\n        fdist = arcpy.Parameter(\n            displayName=\"Flatness distance (cells).\",\n            name=\"fdist\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        fdist.value = '0'\n\n        skip = arcpy.Parameter(\n            displayName=\"Skip distance (cells).\",\n            name=\"skip\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        skip.value = '0'\n\n        forms = arcpy.Parameter(\n            displayName=\"Output forms\",\n            name=\"forms\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        forms.value = 'True'\n\n        residuals = arcpy.Parameter(\n            displayName=\"Analyze residuals\",\n            name=\"residuals\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        residuals.value = 'False'\n\n        params = [dem, output, search, threshold, fdist, skip, forms, residuals]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        search = parameters[2].valueAsText\n        threshold = parameters[3].valueAsText\n        fdist = parameters[4].valueAsText\n        skip = parameters[5].valueAsText\n        forms = parameters[6].valueAsText\n        residuals = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.geomorphons(dem=dem, output=output, search=search, threshold=threshold, fdist=fdist, skip=skip, forms=forms, residuals=residuals)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass GreaterThan(object):\n    def __init__(self):\n        self.label = \"Greater Than\"\n        self.description = \"Performs a greater-than comparison operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        incl_equals = arcpy.Parameter(\n            displayName=\"Perform a greater-than-OR-EQUAL-TO operation?\",\n            name=\"incl_equals\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [input1, input2, output, incl_equals]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        incl_equals = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.greater_than(input1=input1, input2=input2, output=output, incl_equals=incl_equals)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HackStreamOrder(object):\n    def __init__(self):\n        self.label = \"Hack Stream Order\"\n        self.description = \"Assigns the Hack stream order to each tributary in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.hack_stream_order(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HeatMap(object):\n    def __init__(self):\n        self.label = \"Heat Map\"\n        self.description = \"Calculates a heat map, or kernel density estimation (KDE), for an input point set.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Points\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        weight_field = arcpy.Parameter(\n            displayName=\"Weight Field Name (Optional)\",\n            name=\"weight_field\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        bandwidth = arcpy.Parameter(\n            displayName=\"Bandwidth\",\n            name=\"bandwidth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        kernel = arcpy.Parameter(\n            displayName=\"Kernel Type\",\n            name=\"kernel\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        kernel.filter.type = \"ValueList\"\n        kernel.filter.list = ['uniform', 'triangular', 'epanechnikov', 'quartic', 'triweight', 'tricube', 'gaussian', 'cosine', 'logistic', 'sigmoid', 'silverman']\n        kernel.value = 'quartic'\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Output Raster Cell Size (Optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        base = arcpy.Parameter(\n            displayName=\"Base Raster (Optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, weight_field, output, bandwidth, kernel, cell_size, base]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        weight_field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        bandwidth = parameters[3].valueAsText\n        kernel = parameters[4].valueAsText\n        cell_size = parameters[5].valueAsText\n        base = parameters[6].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.heat_map(i=i, weight_field=weight_field, output=output, bandwidth=bandwidth, kernel=kernel, cell_size=cell_size, base=base)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HeightAboveGround(object):\n    def __init__(self):\n        self.label = \"Height Above Ground\"\n        self.description = \"Normalizes a LiDAR point cloud, providing the height above the nearest ground-classified point.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.height_above_ground(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HighPassBilateralFilter(object):\n    def __init__(self):\n        self.label = \"High Pass Bilateral Filter\"\n        self.description = \"Performs a high-pass bilateral filter, by differencing an input image by the bilateral filter by Tomasi and Manduchi (1998).\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        sigma_dist = arcpy.Parameter(\n            displayName=\"Distance Standard Deviation (pixels)\",\n            name=\"sigma_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma_dist.value = '0.75'\n\n        sigma_int = arcpy.Parameter(\n            displayName=\"Intensity Standard Deviation (intensity units)\",\n            name=\"sigma_int\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma_int.value = '1.0'\n\n        params = [i, output, sigma_dist, sigma_int]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        sigma_dist = parameters[2].valueAsText\n        sigma_int = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.high_pass_bilateral_filter(i=i, output=output, sigma_dist=sigma_dist, sigma_int=sigma_int)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HighPassFilter(object):\n    def __init__(self):\n        self.label = \"High Pass Filter\"\n        self.description = \"Performs a high-pass filter on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.high_pass_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HighPassMedianFilter(object):\n    def __init__(self):\n        self.label = \"High Pass Median Filter\"\n        self.description = \"Performs a high pass median filter on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        sig_digits = arcpy.Parameter(\n            displayName=\"Number of Significant Digits\",\n            name=\"sig_digits\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sig_digits.value = '2'\n\n        params = [i, output, filterx, filtery, sig_digits]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        sig_digits = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.high_pass_median_filter(i=i, output=output, filterx=filterx, filtery=filtery, sig_digits=sig_digits)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HighestPosition(object):\n    def __init__(self):\n        self.label = \"Highest Position\"\n        self.description = \"Identifies the stack position of the maximum value within a raster stack on a cell-by-cell basis.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.highest_position(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Hillshade(object):\n    def __init__(self):\n        self.label = \"Hillshade\"\n        self.description = \"Calculates a hillshade raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        azimuth = arcpy.Parameter(\n            displayName=\"Azimuth (degrees)\",\n            name=\"azimuth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        azimuth.value = '315.0'\n\n        altitude = arcpy.Parameter(\n            displayName=\"Altitude (degrees)\",\n            name=\"altitude\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        altitude.value = '30.0'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, azimuth, altitude, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        azimuth = parameters[2].valueAsText\n        altitude = parameters[3].valueAsText\n        zfactor = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.hillshade(dem=dem, output=output, azimuth=azimuth, altitude=altitude, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Hillslopes(object):\n    def __init__(self):\n        self.label = \"Hillslopes\"\n        self.description = \"Identifies the individual hillslopes draining to each link in a stream network.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, streams, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.hillslopes(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HistogramEqualization(object):\n    def __init__(self):\n        self.label = \"Histogram Equalization\"\n        self.description = \"Performs a histogram equalization contrast enhancement on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        num_tones = arcpy.Parameter(\n            displayName=\"Number of Tones\",\n            name=\"num_tones\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_tones.value = '256'\n\n        params = [i, output, num_tones]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        num_tones = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.histogram_equalization(i=i, output=output, num_tones=num_tones)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HistogramMatching(object):\n    def __init__(self):\n        self.label = \"Histogram Matching\"\n        self.description = \"Alters the statistical distribution of a raster image matching it to a specified PDF.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        histo_file = arcpy.Parameter(\n            displayName=\"Input Probability Distribution Function (PDF) Text File\",\n            name=\"histo_file\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, histo_file, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        histo_file = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.histogram_matching(i=i, histo_file=histo_file, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HistogramMatchingTwoImages(object):\n    def __init__(self):\n        self.label = \"Histogram Matching Two Images\"\n        self.description = \"Alters the cumulative distribution function of a raster image to that of another image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File To Modify\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input Reference File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.histogram_matching_two_images(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HoleProportion(object):\n    def __init__(self):\n        self.label = \"Hole Proportion\"\n        self.description = \"Calculates the proportion of the total area of a polygon's holes relative to the area of the polygon's hull.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.hole_proportion(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HorizonAngle(object):\n    def __init__(self):\n        self.label = \"Horizon Angle\"\n        self.description = \"Calculates horizon angle (maximum upwind slope) for each grid cell in an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        azimuth = arcpy.Parameter(\n            displayName=\"Azimuth\",\n            name=\"azimuth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        azimuth.value = '0.0'\n\n        max_dist = arcpy.Parameter(\n            displayName=\"Maximum Search Distance\",\n            name=\"max_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_dist.value = '100.0'\n\n        params = [dem, output, azimuth, max_dist]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        azimuth = parameters[2].valueAsText\n        max_dist = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.horizon_angle(dem=dem, output=output, azimuth=azimuth, max_dist=max_dist)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HorizontalExcessCurvature(object):\n    def __init__(self):\n        self.label = \"Horizontal Excess Curvature\"\n        self.description = \"This tool calculates horizontal excess curvature from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.horizontal_excess_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HortonStreamOrder(object):\n    def __init__(self):\n        self.label = \"Horton Stream Order\"\n        self.description = \"Assigns the Horton stream order to each tributary in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.horton_stream_order(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HydrologicConnectivity(object):\n    def __init__(self):\n        self.label = \"Hydrologic Connectivity\"\n        self.description = \"This tool evaluates hydrologic connectivity within a DEM\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output1 = arcpy.Parameter(\n            displayName=\"Output Downslope Unsaturated Length File\",\n            name=\"output1\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output1.filter.list = [\"tif\"]\n\n        output2 = arcpy.Parameter(\n            displayName=\"Output Upslope Disconnected Saturated Area File\",\n            name=\"output2\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output2.filter.list = [\"tif\"]\n\n        exponent = arcpy.Parameter(\n            displayName=\"Exponent Parameter\",\n            name=\"exponent\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        exponent.value = '1.0'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Convergence Threshold (grid cells; blank for none)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output1, output2, exponent, threshold]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output1 = parameters[1].valueAsText\n        output2 = parameters[2].valueAsText\n        exponent = parameters[3].valueAsText\n        threshold = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.hydrologic_connectivity(dem=dem, output1=output1, output2=output2, exponent=exponent, threshold=threshold)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HypsometricAnalysis(object):\n    def __init__(self):\n        self.label = \"Hypsometric Analysis\"\n        self.description = \"Calculates a hypsometric curve for one or more DEMs.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input DEM Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        watershed = arcpy.Parameter(\n            displayName=\"Input Watershed Files (optional)\",\n            name=\"watershed\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        watershed.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [inputs, watershed, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        watershed = parameters[1].valueAsText\n        if watershed is not None:\n            items = watershed.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            watershed = \";\".join(items_path)\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.hypsometric_analysis(inputs=inputs, watershed=watershed, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HypsometricallyTintedHillshade(object):\n    def __init__(self):\n        self.label = \"Hypsometrically Tinted Hillshade\"\n        self.description = \"Creates an colour shaded relief image from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        altitude = arcpy.Parameter(\n            displayName=\"Illumination Source Altitude (degrees)\",\n            name=\"altitude\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        altitude.value = '45.0'\n\n        hs_weight = arcpy.Parameter(\n            displayName=\"Hillshade Weight\",\n            name=\"hs_weight\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        hs_weight.value = '0.5'\n\n        brightness = arcpy.Parameter(\n            displayName=\"Brightness\",\n            name=\"brightness\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        brightness.value = '0.5'\n\n        atmospheric = arcpy.Parameter(\n            displayName=\"Atmospheric Effects\",\n            name=\"atmospheric\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        atmospheric.value = '0.0'\n\n        palette = arcpy.Parameter(\n            displayName=\"Palette\",\n            name=\"palette\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        palette.filter.type = \"ValueList\"\n        palette.filter.list = ['atlas', 'high_relief', 'arid', 'soft', 'muted', 'purple', 'viridis', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep']\n        palette.value = 'atlas'\n\n        reverse = arcpy.Parameter(\n            displayName=\"Reverse palette?\",\n            name=\"reverse\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        reverse.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        full_mode = arcpy.Parameter(\n            displayName=\"Full 360-degree hillshade mode?\",\n            name=\"full_mode\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        full_mode.value = 'False'\n\n        params = [dem, output, altitude, hs_weight, brightness, atmospheric, palette, reverse, zfactor, full_mode]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        altitude = parameters[2].valueAsText\n        hs_weight = parameters[3].valueAsText\n        brightness = parameters[4].valueAsText\n        atmospheric = parameters[5].valueAsText\n        palette = parameters[6].valueAsText\n        reverse = parameters[7].valueAsText\n        zfactor = parameters[8].valueAsText\n        full_mode = parameters[9].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.hypsometrically_tinted_hillshade(dem=dem, output=output, altitude=altitude, hs_weight=hs_weight, brightness=brightness, atmospheric=atmospheric, palette=palette, reverse=reverse, zfactor=zfactor, full_mode=full_mode)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass IdwInterpolation(object):\n    def __init__(self):\n        self.label = \"Idw Interpolation\"\n        self.description = \"Interpolates vector points into a raster surface using an inverse-distance weighted scheme.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        use_z = arcpy.Parameter(\n            displayName=\"Use z-coordinate instead of field?\",\n            name=\"use_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_z.value = 'False'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        weight = arcpy.Parameter(\n            displayName=\"IDW Weight (Exponent) Value\",\n            name=\"weight\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        weight.value = '2.0'\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius (map units)\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        min_points = arcpy.Parameter(\n            displayName=\"Min. Number of Points\",\n            name=\"min_points\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, use_z, output, weight, radius, min_points, cell_size, base]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        use_z = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        weight = parameters[4].valueAsText\n        radius = parameters[5].valueAsText\n        min_points = parameters[6].valueAsText\n        cell_size = parameters[7].valueAsText\n        base = parameters[8].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.idw_interpolation(i=i, field=field, use_z=use_z, output=output, weight=weight, radius=radius, min_points=min_points, cell_size=cell_size, base=base)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass IhsToRgb(object):\n    def __init__(self):\n        self.label = \"Ihs To Rgb\"\n        self.description = \"Converts intensity, hue, and saturation (IHS) images into red, green, and blue (RGB) images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        intensity = arcpy.Parameter(\n            displayName=\"Input Intensity File\",\n            name=\"intensity\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        hue = arcpy.Parameter(\n            displayName=\"Input Hue File\",\n            name=\"hue\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        saturation = arcpy.Parameter(\n            displayName=\"Input Saturation File\",\n            name=\"saturation\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        red = arcpy.Parameter(\n            displayName=\"Output Red Band File (optional; only if colour-composite not specified)\",\n            name=\"red\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        red.filter.list = [\"tif\"]\n\n        green = arcpy.Parameter(\n            displayName=\"Output Green Band File (optional; only if colour-composite not specified)\",\n            name=\"green\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        green.filter.list = [\"tif\"]\n\n        blue = arcpy.Parameter(\n            displayName=\"Output Blue Band File (optional; only if colour-composite not specified)\",\n            name=\"blue\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        blue.filter.list = [\"tif\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Colour-Composite File (optional; only if individual bands not specified)\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [intensity, hue, saturation, red, green, blue, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        intensity = parameters[0].valueAsText\n        if intensity is not None:\n            desc = arcpy.Describe(intensity)\n            intensity = desc.catalogPath\n        hue = parameters[1].valueAsText\n        if hue is not None:\n            desc = arcpy.Describe(hue)\n            hue = desc.catalogPath\n        saturation = parameters[2].valueAsText\n        if saturation is not None:\n            desc = arcpy.Describe(saturation)\n            saturation = desc.catalogPath\n        red = parameters[3].valueAsText\n        green = parameters[4].valueAsText\n        blue = parameters[5].valueAsText\n        output = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.ihs_to_rgb(intensity=intensity, hue=hue, saturation=saturation, red=red, green=green, blue=blue, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ImageAutocorrelation(object):\n    def __init__(self):\n        self.label = \"Image Autocorrelation\"\n        self.description = \"Performs Moran's I analysis on two or more input images.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        contiguity = arcpy.Parameter(\n            displayName=\"Contiguity Type\",\n            name=\"contiguity\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        contiguity.filter.type = \"ValueList\"\n        contiguity.filter.list = ['Rook', 'King', 'Bishop']\n        contiguity.value = 'Rook'\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [inputs, contiguity, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        contiguity = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.image_autocorrelation(inputs=inputs, contiguity=contiguity, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ImageCorrelation(object):\n    def __init__(self):\n        self.label = \"Image Correlation\"\n        self.description = \"Performs image correlation on two or more input images.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.image_correlation(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ImageCorrelationNeighbourhoodAnalysis(object):\n    def __init__(self):\n        self.label = \"Image Correlation Neighbourhood Analysis\"\n        self.description = \"Performs image correlation on two input images neighbourhood search windows.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Image 1\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Image 2\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output1 = arcpy.Parameter(\n            displayName=\"Output Correlation File\",\n            name=\"output1\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output1.filter.list = [\"tif\"]\n\n        output2 = arcpy.Parameter(\n            displayName=\"Output Significance File\",\n            name=\"output2\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output2.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Size\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '11'\n\n        stat = arcpy.Parameter(\n            displayName=\"Correlation Statistic Type\",\n            name=\"stat\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        stat.filter.type = \"ValueList\"\n        stat.filter.list = ['pearson', 'kendall', 'spearman']\n        stat.value = 'pearson'\n\n        params = [input1, input2, output1, output2, filter, stat]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output1 = parameters[2].valueAsText\n        output2 = parameters[3].valueAsText\n        filter = parameters[4].valueAsText\n        stat = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.image_correlation_neighbourhood_analysis(input1=input1, input2=input2, output1=output1, output2=output2, filter=filter, stat=stat)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ImageRegression(object):\n    def __init__(self):\n        self.label = \"Image Regression\"\n        self.description = \"Performs image regression analysis on two input images.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Independent Variable (X).\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Dependent Variable (Y).\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Summary Report File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        out_residuals = arcpy.Parameter(\n            displayName=\"Optional Residuals Output File\",\n            name=\"out_residuals\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_residuals.filter.list = [\"tif\"]\n\n        standardize = arcpy.Parameter(\n            displayName=\"Standardize the residuals map?\",\n            name=\"standardize\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        scattergram = arcpy.Parameter(\n            displayName=\"Output scattergram?\",\n            name=\"scattergram\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        num_samples = arcpy.Parameter(\n            displayName=\"Num. Samples For Scattergram\",\n            name=\"num_samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_samples.value = '1000'\n\n        params = [input1, input2, output, out_residuals, standardize, scattergram, num_samples]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        out_residuals = parameters[3].valueAsText\n        standardize = parameters[4].valueAsText\n        scattergram = parameters[5].valueAsText\n        num_samples = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.image_regression(input1=input1, input2=input2, output=output, out_residuals=out_residuals, standardize=standardize, scattergram=scattergram, num_samples=num_samples)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ImageSegmentation(object):\n    def __init__(self):\n        self.label = \"Image Segmentation\"\n        self.description = \"Performs a region-growing based segmentation on a set of multi-spectral images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Band Images\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        threshold = arcpy.Parameter(\n            displayName=\"Distance Threshold (z-scores)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        threshold.value = '0.5'\n\n        steps = arcpy.Parameter(\n            displayName=\"Number of Steps\",\n            name=\"steps\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        steps.value = '10'\n\n        min_area = arcpy.Parameter(\n            displayName=\"Min. Object Area (in grid cells)\",\n            name=\"min_area\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_area.value = '4'\n\n        params = [inputs, output, threshold, steps, min_area]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        threshold = parameters[2].valueAsText\n        steps = parameters[3].valueAsText\n        min_area = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.image_segmentation(inputs=inputs, output=output, threshold=threshold, steps=steps, min_area=min_area)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ImageSlider(object):\n    def __init__(self):\n        self.label = \"Image Slider\"\n        self.description = \"This tool creates an image slider from two input images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Left Input Raster Image\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        palette1 = arcpy.Parameter(\n            displayName=\"Left Image Palette\",\n            name=\"palette1\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        palette1.filter.type = \"ValueList\"\n        palette1.filter.list = ['grey', 'atlas', 'high_relief', 'arid', 'soft', 'muted', 'purple', 'viridi', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep', 'rgb']\n        palette1.value = 'grey'\n\n        reverse1 = arcpy.Parameter(\n            displayName=\"Reverse left image palette?\",\n            name=\"reverse1\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        reverse1.value = 'False'\n\n        label1 = arcpy.Parameter(\n            displayName=\"Left Image Label (blank for none)\",\n            name=\"label1\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        input2 = arcpy.Parameter(\n            displayName=\"Right Input Raster Image\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        palette2 = arcpy.Parameter(\n            displayName=\"Right Image Palette\",\n            name=\"palette2\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        palette2.filter.type = \"ValueList\"\n        palette2.filter.list = ['grey', 'atlas', 'high_relief', 'arid', 'soft', 'muted', 'purple', 'viridi', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep', 'rgb']\n        palette2.value = 'grey'\n\n        reverse2 = arcpy.Parameter(\n            displayName=\"Reverse right image palette?\",\n            name=\"reverse2\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        reverse2.value = 'False'\n\n        label2 = arcpy.Parameter(\n            displayName=\"Right Image Label (blank for none)\",\n            name=\"label2\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        output = arcpy.Parameter(\n            displayName=\"Output File (*.html)\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        height = arcpy.Parameter(\n            displayName=\"Image Height (in pixels)\",\n            name=\"height\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        height.value = '600'\n\n        params = [input1, palette1, reverse1, label1, input2, palette2, reverse2, label2, output, height]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        palette1 = parameters[1].valueAsText\n        reverse1 = parameters[2].valueAsText\n        label1 = parameters[3].valueAsText\n        input2 = parameters[4].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        palette2 = parameters[5].valueAsText\n        reverse2 = parameters[6].valueAsText\n        label2 = parameters[7].valueAsText\n        output = parameters[8].valueAsText\n        height = parameters[9].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.image_slider(input1=input1, palette1=palette1, reverse1=reverse1, label1=label1, input2=input2, palette2=palette2, reverse2=reverse2, label2=label2, output=output, height=height)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ImageStackProfile(object):\n    def __init__(self):\n        self.label = \"Image Stack Profile\"\n        self.description = \"Plots an image stack profile (i.e. signature) for a set of points and multispectral images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        points = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"points\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        points.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [inputs, points, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        points = parameters[1].valueAsText\n        if points is not None:\n            desc = arcpy.Describe(points)\n            points = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.image_stack_profile(inputs=inputs, points=points, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ImpoundmentSizeIndex(object):\n    def __init__(self):\n        self.label = \"Impoundment Size Index\"\n        self.description = \"Calculates the impoundment size resulting from damming a DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_mean = arcpy.Parameter(\n            displayName=\"Output Mean Depth File\",\n            name=\"out_mean\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_mean.filter.list = [\"tif\"]\n\n        out_max = arcpy.Parameter(\n            displayName=\"Output Max. Depth File\",\n            name=\"out_max\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_max.filter.list = [\"tif\"]\n\n        out_volume = arcpy.Parameter(\n            displayName=\"Output Volume File\",\n            name=\"out_volume\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_volume.filter.list = [\"tif\"]\n\n        out_area = arcpy.Parameter(\n            displayName=\"Output Area File\",\n            name=\"out_area\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_area.filter.list = [\"tif\"]\n\n        out_dam_height = arcpy.Parameter(\n            displayName=\"Output Dam Height File\",\n            name=\"out_dam_height\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_dam_height.filter.list = [\"tif\"]\n\n        damlength = arcpy.Parameter(\n            displayName=\"Max dam length (grid cells)\",\n            name=\"damlength\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [dem, out_mean, out_max, out_volume, out_area, out_dam_height, damlength]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        out_mean = parameters[1].valueAsText\n        out_max = parameters[2].valueAsText\n        out_volume = parameters[3].valueAsText\n        out_area = parameters[4].valueAsText\n        out_dam_height = parameters[5].valueAsText\n        damlength = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.impoundment_size_index(dem=dem, out_mean=out_mean, out_max=out_max, out_volume=out_volume, out_area=out_area, out_dam_height=out_dam_height, damlength=damlength)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass InPlaceAdd(object):\n    def __init__(self):\n        self.label = \"In Place Add\"\n        self.description = \"Performs an in-place addition operation (input1 += input2).\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input Raster File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [input1, input2]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.in_place_add(input1=input1, input2=input2)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass InPlaceDivide(object):\n    def __init__(self):\n        self.label = \"In Place Divide\"\n        self.description = \"Performs an in-place division operation (input1 /= input2).\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input Raster File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [input1, input2]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.in_place_divide(input1=input1, input2=input2)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass InPlaceMultiply(object):\n    def __init__(self):\n        self.label = \"In Place Multiply\"\n        self.description = \"Performs an in-place multiplication operation (input1 *= input2).\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input Raster File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [input1, input2]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.in_place_multiply(input1=input1, input2=input2)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass InPlaceSubtract(object):\n    def __init__(self):\n        self.label = \"In Place Subtract\"\n        self.description = \"Performs an in-place subtraction operation (input1 -= input2).\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input Raster File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [input1, input2]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.in_place_subtract(input1=input1, input2=input2)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Increment(object):\n    def __init__(self):\n        self.label = \"Increment\"\n        self.description = \"Increases the values of each grid cell in an input raster by 1.0. (see also InPlaceAdd)\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.increment(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass IndividualTreeDetection(object):\n    def __init__(self):\n        self.label = \"Individual Tree Detection\"\n        self.description = \"Identifies points in a LiDAR point cloud that are associated with the tops of individual trees.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        min_search_radius = arcpy.Parameter(\n            displayName=\"Min. Search Radius\",\n            name=\"min_search_radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        min_search_radius.value = '1.0'\n\n        min_height = arcpy.Parameter(\n            displayName=\"Min. Height\",\n            name=\"min_height\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        min_height.value = '0.0'\n\n        max_search_radius = arcpy.Parameter(\n            displayName=\"Max. Search Radius\",\n            name=\"max_search_radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_height = arcpy.Parameter(\n            displayName=\"Max. Height\",\n            name=\"max_height\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        only_use_veg = arcpy.Parameter(\n            displayName=\"Only use veg. class points?\",\n            name=\"only_use_veg\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        only_use_veg.value = 'False'\n\n        params = [i, output, min_search_radius, min_height, max_search_radius, max_height, only_use_veg]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        min_search_radius = parameters[2].valueAsText\n        min_height = parameters[3].valueAsText\n        max_search_radius = parameters[4].valueAsText\n        max_height = parameters[5].valueAsText\n        only_use_veg = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.individual_tree_detection(i=i, output=output, min_search_radius=min_search_radius, min_height=min_height, max_search_radius=max_search_radius, max_height=max_height, only_use_veg=only_use_veg)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass InsertDams(object):\n    def __init__(self):\n        self.label = \"Insert Dams\"\n        self.description = \"Calculates the impoundment size resulting from damming a DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        dam_pts = arcpy.Parameter(\n            displayName=\"Input Dam Points\",\n            name=\"dam_pts\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        dam_pts.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        damlength = arcpy.Parameter(\n            displayName=\"Max dam length (grid cells)\",\n            name=\"damlength\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [dem, dam_pts, output, damlength]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        dam_pts = parameters[1].valueAsText\n        if dam_pts is not None:\n            desc = arcpy.Describe(dam_pts)\n            dam_pts = desc.catalogPath\n        output = parameters[2].valueAsText\n        damlength = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.insert_dams(dem=dem, dam_pts=dam_pts, output=output, damlength=damlength)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass InstallWbExtension(object):\n    def __init__(self):\n        self.label = \"Install Wb Extension\"\n        self.description = \"Use to install a Whitebox extension product.\"\n        self.category = \"Whitebox Utilities\"\n\n    def getParameterInfo(self):\n        install_extension = arcpy.Parameter(\n            displayName=\"Whitebox Extension Product Name\",\n            name=\"install_extension\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        install_extension.filter.type = \"ValueList\"\n        install_extension.filter.list = ['General Toolset Extension', 'DEM & Spatial Hydrology Extension', 'Lidar & Remote Sensing Extension', 'Agriculture Extension']\n        install_extension.value = 'General Toolset Extension'\n\n        params = [install_extension]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        install_extension = parameters[0].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.install_wb_extension(install_extension=install_extension)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass IntegerDivision(object):\n    def __init__(self):\n        self.label = \"Integer Division\"\n        self.description = \"Performs an integer division operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.integer_division(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass IntegralImage(object):\n    def __init__(self):\n        self.label = \"Integral Image\"\n        self.description = \"Transforms an input image (summed area table) into its integral image equivalent.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.integral_image(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Intersect(object):\n    def __init__(self):\n        self.label = \"Intersect\"\n        self.description = \"Identifies the parts of features in common between two input vector layers.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        overlay = arcpy.Parameter(\n            displayName=\"Input Overlay Vector File\",\n            name=\"overlay\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        snap = arcpy.Parameter(\n            displayName=\"Snap Tolerance\",\n            name=\"snap\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        snap.value = '0.0'\n\n        params = [i, overlay, output, snap]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        overlay = parameters[1].valueAsText\n        if overlay is not None:\n            desc = arcpy.Describe(overlay)\n            overlay = desc.catalogPath\n        output = parameters[2].valueAsText\n        snap = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.intersect(i=i, overlay=overlay, output=output, snap=snap)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass InversePrincipalComponentAnalysis(object):\n    def __init__(self):\n        self.label = \"Inverse Pca\"\n        self.description = \"This tool performs an inverse principal component analysis on a series of input component images.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input PCA Component Images\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        report = arcpy.Parameter(\n            displayName=\"Input PCA Report File\",\n            name=\"report\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        report.filter.list = [\"html\"]\n\n        params = [inputs, report]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        report = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.inverse_principal_component_analysis(inputs=inputs, report=report)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass IsNoData(object):\n    def __init__(self):\n        self.label = \"Is No Data\"\n        self.description = \"Identifies NoData valued pixels in an image.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.is_no_data(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Isobasins(object):\n    def __init__(self):\n        self.label = \"Isobasins\"\n        self.description = \"Divides a landscape into nearly equal sized drainage basins (i.e. watersheds).\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        size = arcpy.Parameter(\n            displayName=\"Target Basin Size (grid cells)\",\n            name=\"size\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        connections = arcpy.Parameter(\n            displayName=\"Output basin upstream-downstream connections?\",\n            name=\"connections\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        connections.value = 'False'\n\n        params = [dem, output, size, connections]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        size = parameters[2].valueAsText\n        connections = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.isobasins(dem=dem, output=output, size=size, connections=connections)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass JensonSnapPourPoints(object):\n    def __init__(self):\n        self.label = \"Jenson Snap Pour Points\"\n        self.description = \"Moves outlet points used to specify points of interest in a watershedding operation to the nearest stream cell.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        pour_pts = arcpy.Parameter(\n            displayName=\"Input Pour Points (Outlet) File\",\n            name=\"pour_pts\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        pour_pts.filter.list = [\"Point\"]\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        snap_dist = arcpy.Parameter(\n            displayName=\"Maximum Snap Distance (map units)\",\n            name=\"snap_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [pour_pts, streams, output, snap_dist]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        pour_pts = parameters[0].valueAsText\n        if pour_pts is not None:\n            desc = arcpy.Describe(pour_pts)\n            pour_pts = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        snap_dist = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.jenson_snap_pour_points(pour_pts=pour_pts, streams=streams, output=output, snap_dist=snap_dist)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass JoinTables(object):\n    def __init__(self):\n        self.label = \"Join Tables\"\n        self.description = \"Merge a vector's attribute table with another table based on a common field.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input Primary Vector File\",\n            name=\"input1\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        pkey = arcpy.Parameter(\n            displayName=\"Primary Key Field\",\n            name=\"pkey\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        pkey.parameterDependencies = [input1.name]\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input Foreign Vector File\",\n            name=\"input2\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        fkey = arcpy.Parameter(\n            displayName=\"Foreign Key Field\",\n            name=\"fkey\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        fkey.parameterDependencies = [input2.name]\n\n        import_field = arcpy.Parameter(\n            displayName=\"Imported Field\",\n            name=\"import_field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        import_field.parameterDependencies = [input2.name]\n\n        params = [input1, pkey, input2, fkey, import_field]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        pkey = parameters[1].valueAsText\n        input2 = parameters[2].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        fkey = parameters[3].valueAsText\n        import_field = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.join_tables(input1=input1, pkey=pkey, input2=input2, fkey=fkey, import_field=import_field)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass KMeansClustering(object):\n    def __init__(self):\n        self.label = \"K Means Clustering\"\n        self.description = \"Performs a k-means clustering operation on a multi-spectral dataset.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_html = arcpy.Parameter(\n            displayName=\"Output HTML Report File\",\n            name=\"out_html\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_html.filter.list = [\"html\"]\n\n        classes = arcpy.Parameter(\n            displayName=\"Num. Classes (k)\",\n            name=\"classes\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        max_iterations = arcpy.Parameter(\n            displayName=\"Max. Iterations\",\n            name=\"max_iterations\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_iterations.value = '10'\n\n        class_change = arcpy.Parameter(\n            displayName=\"Percent Class Change Threshold\",\n            name=\"class_change\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        class_change.value = '2.0'\n\n        initialize = arcpy.Parameter(\n            displayName=\"How to Initialize Cluster Centres?\",\n            name=\"initialize\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        initialize.filter.type = \"ValueList\"\n        initialize.filter.list = ['diagonal', 'random']\n        initialize.value = 'diagonal'\n\n        min_class_size = arcpy.Parameter(\n            displayName=\"Min. Class Size\",\n            name=\"min_class_size\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_class_size.value = '10'\n\n        params = [inputs, output, out_html, classes, max_iterations, class_change, initialize, min_class_size]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        out_html = parameters[2].valueAsText\n        classes = parameters[3].valueAsText\n        max_iterations = parameters[4].valueAsText\n        class_change = parameters[5].valueAsText\n        initialize = parameters[6].valueAsText\n        min_class_size = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.k_means_clustering(inputs=inputs, output=output, out_html=out_html, classes=classes, max_iterations=max_iterations, class_change=class_change, initialize=initialize, min_class_size=min_class_size)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass KNearestMeanFilter(object):\n    def __init__(self):\n        self.label = \"K Nearest Mean Filter\"\n        self.description = \"A k-nearest mean filter is a type of edge-preserving smoothing filter.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        k = arcpy.Parameter(\n            displayName=\"K-value (pixels)\",\n            name=\"k\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        k.value = '5'\n\n        params = [i, output, filterx, filtery, k]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        k = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.k_nearest_mean_filter(i=i, output=output, filterx=filterx, filtery=filtery, k=k)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass KappaIndex(object):\n    def __init__(self):\n        self.label = \"Kappa Index\"\n        self.description = \"Performs a kappa index of agreement (KIA) analysis on two categorical raster files.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input Classification File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input Reference File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.kappa_index(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass KnnClassification(object):\n    def __init__(self):\n        self.label = \"Knn Classification\"\n        self.description = \"Performs a supervised k-nearest neighbour classification using training site polygons/points and predictor rasters.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Predictor Rasters\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        training = arcpy.Parameter(\n            displayName=\"Input Training Polygons/Points\",\n            name=\"training\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        field = arcpy.Parameter(\n            displayName=\"Class Name Field\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [training.name]\n\n        test_proportion = arcpy.Parameter(\n            displayName=\"Test Proportion\",\n            name=\"test_proportion\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        test_proportion.value = '0.2'\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        scaling = arcpy.Parameter(\n            displayName=\"Scaling Method\",\n            name=\"scaling\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        scaling.filter.type = \"ValueList\"\n        scaling.filter.list = ['None', 'Normalize', 'Standardize']\n        scaling.value = 'Normalize'\n\n        k = arcpy.Parameter(\n            displayName=\"Number of Nearest Neighbours, k\",\n            name=\"k\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        k.value = '5'\n\n        clip = arcpy.Parameter(\n            displayName=\"Perform training data clipping?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = 'True'\n\n        params = [inputs, training, field, test_proportion, output, scaling, k, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        training = parameters[1].valueAsText\n        if training is not None:\n            desc = arcpy.Describe(training)\n            training = desc.catalogPath\n        field = parameters[2].valueAsText\n        test_proportion = parameters[3].valueAsText\n        output = parameters[4].valueAsText\n        scaling = parameters[5].valueAsText\n        k = parameters[6].valueAsText\n        clip = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.knn_classification(inputs=inputs, training=training, field=field, test_proportion=test_proportion, output=output, scaling=scaling, k=k, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass KnnRegression(object):\n    def __init__(self):\n        self.label = \"Knn Regression\"\n        self.description = \"Performs a supervised k-nearest neighbour regression using training site points and predictor rasters.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Predictor Rasters\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        scaling = arcpy.Parameter(\n            displayName=\"Scaling Method\",\n            name=\"scaling\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        scaling.filter.type = \"ValueList\"\n        scaling.filter.list = ['None', 'Normalize', 'Standardize']\n        scaling.value = 'Normalize'\n\n        training = arcpy.Parameter(\n            displayName=\"Input Training Points\",\n            name=\"training\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        training.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Response Variable Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [training.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        k = arcpy.Parameter(\n            displayName=\"Number of Nearest Neighbours, k\",\n            name=\"k\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        k.value = '5'\n\n        weight = arcpy.Parameter(\n            displayName=\"Use distance weighting?\",\n            name=\"weight\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        weight.value = 'True'\n\n        test_proportion = arcpy.Parameter(\n            displayName=\"Test Proportion\",\n            name=\"test_proportion\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        test_proportion.value = '0.2'\n\n        params = [inputs, scaling, training, field, output, k, weight, test_proportion]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        scaling = parameters[1].valueAsText\n        training = parameters[2].valueAsText\n        if training is not None:\n            desc = arcpy.Describe(training)\n            training = desc.catalogPath\n        field = parameters[3].valueAsText\n        output = parameters[4].valueAsText\n        k = parameters[5].valueAsText\n        weight = parameters[6].valueAsText\n        test_proportion = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.knn_regression(inputs=inputs, scaling=scaling, training=training, field=field, output=output, k=k, weight=weight, test_proportion=test_proportion)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass KsTestForNormality(object):\n    def __init__(self):\n        self.label = \"Ks Test For Normality\"\n        self.description = \"Evaluates whether the values in a raster are normally distributed.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        num_samples = arcpy.Parameter(\n            displayName=\"Num. Samples (blank for while image)\",\n            name=\"num_samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, num_samples]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        num_samples = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.ks_test_for_normality(i=i, output=output, num_samples=num_samples)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LaplacianFilter(object):\n    def __init__(self):\n        self.label = \"Laplacian Filter\"\n        self.description = \"Performs a Laplacian filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        variant = arcpy.Parameter(\n            displayName=\"Variant\",\n            name=\"variant\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        variant.filter.type = \"ValueList\"\n        variant.filter.list = ['3x3(1)', '3x3(2)', '3x3(3)', '3x3(4)', '5x5(1)', '5x5(2)']\n        variant.value = '3x3(1)'\n\n        clip = arcpy.Parameter(\n            displayName=\"Distribution Tail Clip Amount (%)\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '0.0'\n\n        params = [i, output, variant, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        variant = parameters[2].valueAsText\n        clip = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.laplacian_filter(i=i, output=output, variant=variant, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LaplacianOfGaussianFilter(object):\n    def __init__(self):\n        self.label = \"Laplacian Of Gaussian Filter\"\n        self.description = \"Performs a Laplacian-of-Gaussian (LoG) filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        sigma = arcpy.Parameter(\n            displayName=\"Standard Deviation (Pixels)\",\n            name=\"sigma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma.value = '0.75'\n\n        params = [i, output, sigma]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        sigma = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.laplacian_of_gaussian_filter(i=i, output=output, sigma=sigma)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LasToAscii(object):\n    def __init__(self):\n        self.label = \"Las To Ascii\"\n        self.description = \"Converts one or more LAS files into ASCII text files.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input LiDAR Files\",\n            name=\"inputs\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n        inputs.filter.list = [\"las\", \"zip\"]\n\n        params = [inputs]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.las_to_ascii(inputs=inputs)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LasToLaz(object):\n    def __init__(self):\n        self.label = \"Las To Laz\"\n        self.description = \"This tool converts one or more LAS files into the LAZ format\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LAS File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LAZ File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.las_to_laz(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LasToMultipointShapefile(object):\n    def __init__(self):\n        self.label = \"Las To Multipoint Shapefile\"\n        self.description = \"Converts one or more LAS files into MultipointZ vector Shapefiles. When the input parameter is not specified, the tool grids all LAS files contained within the working directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.las_to_multipoint_shapefile(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LasToShapefile(object):\n    def __init__(self):\n        self.label = \"Las To Shapefile\"\n        self.description = \"Converts one or more LAS files into a vector Shapefile of POINT ShapeType.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.las_to_shapefile(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LasToZlidar(object):\n    def __init__(self):\n        self.label = \"Las To Zlidar\"\n        self.description = \"Converts one or more LAS files into the zlidar compressed LiDAR data format.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input LAS Files\",\n            name=\"inputs\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        inputs.multiValue = True\n        inputs.filter.list = [\"las\", \"zip\"]\n\n        outdir = arcpy.Parameter(\n            displayName=\"Output Directory\",\n            name=\"outdir\",\n            datatype=\"DEFolder\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        compress = arcpy.Parameter(\n            displayName=\"Compression Method\",\n            name=\"compress\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        compress.filter.type = \"ValueList\"\n        compress.filter.list = ['brotli', 'deflate']\n        compress.value = 'brotli'\n\n        level = arcpy.Parameter(\n            displayName=\"Compression Level\",\n            name=\"level\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        level.value = '5'\n\n        params = [inputs, outdir, compress, level]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        outdir = parameters[1].valueAsText\n        compress = parameters[2].valueAsText\n        level = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.las_to_zlidar(inputs=inputs, outdir=outdir, compress=compress, level=level)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LaunchWbRunner(object):\n    def __init__(self):\n        self.label = \"Launch Wb Runner\"\n        self.description = \"Opens the Whitebox Runner application.\"\n        self.category = \"Whitebox Utilities\"\n\n    def getParameterInfo(self):\n        clear_app_state = arcpy.Parameter(\n            displayName=\"Clear the application state memory?\",\n            name=\"clear_app_state\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clear_app_state.value = 'False'\n\n        params = [clear_app_state]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        clear_app_state = parameters[0].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.launch_wb_runner(clear_app_state=clear_app_state)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LayerFootprint(object):\n    def __init__(self):\n        self.label = \"Layer Footprint\"\n        self.description = \"Creates a vector polygon footprint of the area covered by a raster grid or vector layer.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster or Vector File\",\n            name=\"i\",\n            datatype=[\"DERasterDataset\", \"DEShapefile\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.layer_footprint(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LazToLas(object):\n    def __init__(self):\n        self.label = \"Laz To Las\"\n        self.description = \"This tool converts one or more LAZ files into the LAS format\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LAZ File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LAS File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.laz_to_las(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LeeSigmaFilter(object):\n    def __init__(self):\n        self.label = \"Lee Sigma Filter\"\n        self.description = \"Performs a Lee (Sigma) smoothing filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        sigma = arcpy.Parameter(\n            displayName=\"Sigma\",\n            name=\"sigma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma.value = '10.0'\n\n        m = arcpy.Parameter(\n            displayName=\"M-value\",\n            name=\"m\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        m.value = '5.0'\n\n        params = [i, output, filterx, filtery, sigma, m]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        sigma = parameters[4].valueAsText\n        m = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lee_sigma_filter(i=i, output=output, filterx=filterx, filtery=filtery, sigma=sigma, m=m)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LengthOfUpstreamChannels(object):\n    def __init__(self):\n        self.label = \"Length Of Upstream Channels\"\n        self.description = \"Calculates the total length of channels upstream.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.length_of_upstream_channels(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LessThan(object):\n    def __init__(self):\n        self.label = \"Less Than\"\n        self.description = \"Performs a less-than comparison operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        incl_equals = arcpy.Parameter(\n            displayName=\"Perform a less-than-OR-EQUAL-TO operation?\",\n            name=\"incl_equals\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [input1, input2, output, incl_equals]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        incl_equals = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.less_than(input1=input1, input2=input2, output=output, incl_equals=incl_equals)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarBlockMaximum(object):\n    def __init__(self):\n        self.label = \"Lidar Block Maximum\"\n        self.description = \"Creates a block-maximum raster from an input LAS file. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        params = [i, output, resolution]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        resolution = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_block_maximum(i=i, output=output, resolution=resolution)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarBlockMinimum(object):\n    def __init__(self):\n        self.label = \"Lidar Block Minimum\"\n        self.description = \"Creates a block-minimum raster from an input LAS file. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        params = [i, output, resolution]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        resolution = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_block_minimum(i=i, output=output, resolution=resolution)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarClassifySubset(object):\n    def __init__(self):\n        self.label = \"Lidar Classify Subset\"\n        self.description = \"Classifies the values in one LiDAR point cloud that correspond with points in a subset cloud.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        base = arcpy.Parameter(\n            displayName=\"Input Base LiDAR File\",\n            name=\"base\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        base.filter.list = [\"las\", \"zip\"]\n\n        subset = arcpy.Parameter(\n            displayName=\"Input Subset LiDAR File\",\n            name=\"subset\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        subset.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        subset_class = arcpy.Parameter(\n            displayName=\"Subset Point Class Value\",\n            name=\"subset_class\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        nonsubset_class = arcpy.Parameter(\n            displayName=\"Non-Subset Point Class Value (Optional)\",\n            name=\"nonsubset_class\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [base, subset, output, subset_class, nonsubset_class]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        base = parameters[0].valueAsText\n        subset = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        subset_class = parameters[3].valueAsText\n        nonsubset_class = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_classify_subset(base=base, subset=subset, output=output, subset_class=subset_class, nonsubset_class=nonsubset_class)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarColourize(object):\n    def __init__(self):\n        self.label = \"Lidar Colourize\"\n        self.description = \"Adds the red-green-blue colour fields of a LiDAR (LAS) file based on an input image.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        in_lidar = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"in_lidar\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        in_lidar.filter.list = [\"las\", \"zip\"]\n\n        in_image = arcpy.Parameter(\n            displayName=\"Input Colour Image File\",\n            name=\"in_image\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [in_lidar, in_image, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        in_lidar = parameters[0].valueAsText\n        in_image = parameters[1].valueAsText\n        if in_image is not None:\n            desc = arcpy.Describe(in_image)\n            in_image = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_colourize(in_lidar=in_lidar, in_image=in_image, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarContour(object):\n    def __init__(self):\n        self.label = \"Lidar Contour\"\n        self.description = \"This tool creates a vector contour coverage from an input LiDAR point file.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector Lines\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        interval = arcpy.Parameter(\n            displayName=\"Contour Interval\",\n            name=\"interval\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        interval.value = '10.0'\n\n        base = arcpy.Parameter(\n            displayName=\"Base Contour\",\n            name=\"base\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        base.value = '0.0'\n\n        smooth = arcpy.Parameter(\n            displayName=\"Smoothing Filter Size\",\n            name=\"smooth\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        smooth.value = '5'\n\n        parameter = arcpy.Parameter(\n            displayName=\"Interpolation Parameter\",\n            name=\"parameter\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        parameter.filter.type = \"ValueList\"\n        parameter.filter.list = ['elevation', 'intensity', 'user_data']\n        parameter.value = 'elevation'\n\n        returns = arcpy.Parameter(\n            displayName=\"Point Returns Included\",\n            name=\"returns\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        returns.filter.type = \"ValueList\"\n        returns.filter.list = ['all', 'last', 'first']\n        returns.value = 'all'\n\n        exclude_cls = arcpy.Parameter(\n            displayName=\"Exclusion Classes (0-18, based on LAS spec; e.g. 3,4,5,6,7)\",\n            name=\"exclude_cls\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        minz = arcpy.Parameter(\n            displayName=\"Minimum Elevation Value (optional)\",\n            name=\"minz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        maxz = arcpy.Parameter(\n            displayName=\"Maximum Elevation Value (optional)\",\n            name=\"maxz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_triangle_edge_length = arcpy.Parameter(\n            displayName=\"Maximum Triangle Length (optional)\",\n            name=\"max_triangle_edge_length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, interval, base, smooth, parameter, returns, exclude_cls, minz, maxz, max_triangle_edge_length]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        interval = parameters[2].valueAsText\n        base = parameters[3].valueAsText\n        smooth = parameters[4].valueAsText\n        parameter = parameters[5].valueAsText\n        returns = parameters[6].valueAsText\n        exclude_cls = parameters[7].valueAsText\n        minz = parameters[8].valueAsText\n        maxz = parameters[9].valueAsText\n        max_triangle_edge_length = parameters[10].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_contour(i=i, output=output, interval=interval, base=base, smooth=smooth, parameter=parameter, returns=returns, exclude_cls=exclude_cls, minz=minz, maxz=maxz, max_triangle_edge_length=max_triangle_edge_length)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarDigitalSurfaceModel(object):\n    def __init__(self):\n        self.label = \"Lidar Digital Surface Model\"\n        self.description = \"Creates a top-surface digital surface model (DSM) from a LiDAR point cloud.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '0.5'\n\n        minz = arcpy.Parameter(\n            displayName=\"Minimum Elevation Value (optional)\",\n            name=\"minz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        maxz = arcpy.Parameter(\n            displayName=\"Maximum Elevation Value (optional)\",\n            name=\"maxz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_triangle_edge_length = arcpy.Parameter(\n            displayName=\"Maximum Triangle Edge Length (optional)\",\n            name=\"max_triangle_edge_length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, resolution, radius, minz, maxz, max_triangle_edge_length]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        resolution = parameters[2].valueAsText\n        radius = parameters[3].valueAsText\n        minz = parameters[4].valueAsText\n        maxz = parameters[5].valueAsText\n        max_triangle_edge_length = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_digital_surface_model(i=i, output=output, resolution=resolution, radius=radius, minz=minz, maxz=maxz, max_triangle_edge_length=max_triangle_edge_length)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarEigenvalueFeatures(object):\n    def __init__(self):\n        self.label = \"Lidar Eigenvalue Features\"\n        self.description = \"Calculate eigenvalue-based metrics from a LiDAR point cloud.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        num_neighbours = arcpy.Parameter(\n            displayName=\"Number of Neighbours:\",\n            name=\"num_neighbours\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Distance:\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, num_neighbours, radius]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        num_neighbours = parameters[1].valueAsText\n        radius = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_eigenvalue_features(i=i, num_neighbours=num_neighbours, radius=radius)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarElevationSlice(object):\n    def __init__(self):\n        self.label = \"Lidar Elevation Slice\"\n        self.description = \"Outputs all of the points within a LiDAR (LAS) point file that lie between a specified elevation range.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        minz = arcpy.Parameter(\n            displayName=\"Minimum Elevation Value\",\n            name=\"minz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        maxz = arcpy.Parameter(\n            displayName=\"Maximum Elevation Value\",\n            name=\"maxz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        cls = arcpy.Parameter(\n            displayName=\"Retain but reclass points outside the specified elevation range?\",\n            name=\"cls\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        inclassval = arcpy.Parameter(\n            displayName=\"Class Value Assigned to Points Within Range (Optional)\",\n            name=\"inclassval\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        inclassval.value = '2'\n\n        outclassval = arcpy.Parameter(\n            displayName=\"Class Value Assigned to Points Outside Range (Optional)\",\n            name=\"outclassval\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        outclassval.value = '1'\n\n        params = [i, output, minz, maxz, cls, inclassval, outclassval]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        minz = parameters[2].valueAsText\n        maxz = parameters[3].valueAsText\n        cls = parameters[4].valueAsText\n        inclassval = parameters[5].valueAsText\n        outclassval = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_elevation_slice(i=i, output=output, minz=minz, maxz=maxz, cls=cls, inclassval=inclassval, outclassval=outclassval)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarGroundPointFilter(object):\n    def __init__(self):\n        self.label = \"Lidar Ground Point Filter\"\n        self.description = \"Identifies ground points within LiDAR dataset using a slope-based method.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        radius.value = '2.0'\n\n        min_neighbours = arcpy.Parameter(\n            displayName=\"Minimum Number of Neighbours\",\n            name=\"min_neighbours\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_neighbours.value = '0'\n\n        slope_threshold = arcpy.Parameter(\n            displayName=\"Inter-point Slope Threshold\",\n            name=\"slope_threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        slope_threshold.value = '45.0'\n\n        height_threshold = arcpy.Parameter(\n            displayName=\"Off-terrain Point Height Threshold\",\n            name=\"height_threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        height_threshold.value = '1.0'\n\n        classify = arcpy.Parameter(\n            displayName=\"Classify Points\",\n            name=\"classify\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        classify.value = 'True'\n\n        slope_norm = arcpy.Parameter(\n            displayName=\"Perform initial ground slope normalization?\",\n            name=\"slope_norm\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        slope_norm.value = 'True'\n\n        height_above_ground = arcpy.Parameter(\n            displayName=\"Transform output to height above average ground elevation?\",\n            name=\"height_above_ground\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        height_above_ground.value = 'False'\n\n        params = [i, output, radius, min_neighbours, slope_threshold, height_threshold, classify, slope_norm, height_above_ground]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        radius = parameters[2].valueAsText\n        min_neighbours = parameters[3].valueAsText\n        slope_threshold = parameters[4].valueAsText\n        height_threshold = parameters[5].valueAsText\n        classify = parameters[6].valueAsText\n        slope_norm = parameters[7].valueAsText\n        height_above_ground = parameters[8].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_ground_point_filter(i=i, output=output, radius=radius, min_neighbours=min_neighbours, slope_threshold=slope_threshold, height_threshold=height_threshold, classify=classify, slope_norm=slope_norm, height_above_ground=height_above_ground)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarHexBinning(object):\n    def __init__(self):\n        self.label = \"Lidar Hex Binning\"\n        self.description = \"Hex-bins a set of LiDAR points.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        width = arcpy.Parameter(\n            displayName=\"Hexagon Width\",\n            name=\"width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        orientation = arcpy.Parameter(\n            displayName=\"Grid Orientation\",\n            name=\"orientation\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        orientation.filter.type = \"ValueList\"\n        orientation.filter.list = ['horizontal', 'vertical']\n        orientation.value = 'horizontal'\n\n        params = [i, output, width, orientation]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        width = parameters[2].valueAsText\n        orientation = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_hex_binning(i=i, output=output, width=width, orientation=orientation)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarHillshade(object):\n    def __init__(self):\n        self.label = \"Lidar Hillshade\"\n        self.description = \"Calculates a hillshade value for points within a LAS file and stores these data in the RGB field.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        azimuth = arcpy.Parameter(\n            displayName=\"Azimuth (degrees)\",\n            name=\"azimuth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        azimuth.value = '315.0'\n\n        altitude = arcpy.Parameter(\n            displayName=\"Altitude (degrees)\",\n            name=\"altitude\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        altitude.value = '30.0'\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        radius.value = '1.0'\n\n        params = [i, output, azimuth, altitude, radius]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        azimuth = parameters[2].valueAsText\n        altitude = parameters[3].valueAsText\n        radius = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_hillshade(i=i, output=output, azimuth=azimuth, altitude=altitude, radius=radius)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarHistogram(object):\n    def __init__(self):\n        self.label = \"Lidar Histogram\"\n        self.description = \"Creates a histogram of LiDAR data.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        parameter = arcpy.Parameter(\n            displayName=\"Parameter\",\n            name=\"parameter\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        parameter.filter.type = \"ValueList\"\n        parameter.filter.list = ['elevation', 'intensity', 'scan angle', 'class', 'time']\n        parameter.value = 'elevation'\n\n        clip = arcpy.Parameter(\n            displayName=\"Tail Clip Percent\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '1.0'\n\n        params = [i, output, parameter, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        parameter = parameters[2].valueAsText\n        clip = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_histogram(i=i, output=output, parameter=parameter, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarIdwInterpolation(object):\n    def __init__(self):\n        self.label = \"Lidar Idw Interpolation\"\n        self.description = \"Interpolates LAS files using an inverse-distance weighted (IDW) scheme. When the input/output parameters are not specified, the tool interpolates all LAS files contained within the working directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        parameter = arcpy.Parameter(\n            displayName=\"Interpolation Parameter\",\n            name=\"parameter\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        parameter.filter.type = \"ValueList\"\n        parameter.filter.list = ['elevation', 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data']\n        parameter.value = 'elevation'\n\n        returns = arcpy.Parameter(\n            displayName=\"Point Returns Included\",\n            name=\"returns\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        returns.filter.type = \"ValueList\"\n        returns.filter.list = ['all', 'last', 'first']\n        returns.value = 'all'\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        weight = arcpy.Parameter(\n            displayName=\"IDW Weight (Exponent) Value\",\n            name=\"weight\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        weight.value = '1.0'\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '2.5'\n\n        exclude_cls = arcpy.Parameter(\n            displayName=\"Exclusion Classes (0-18, based on LAS spec; e.g. 3,4,5,6,7)\",\n            name=\"exclude_cls\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        minz = arcpy.Parameter(\n            displayName=\"Minimum Elevation Value (optional)\",\n            name=\"minz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        maxz = arcpy.Parameter(\n            displayName=\"Maximum Elevation Value (optional)\",\n            name=\"maxz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, parameter, returns, resolution, weight, radius, exclude_cls, minz, maxz]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        parameter = parameters[2].valueAsText\n        returns = parameters[3].valueAsText\n        resolution = parameters[4].valueAsText\n        weight = parameters[5].valueAsText\n        radius = parameters[6].valueAsText\n        exclude_cls = parameters[7].valueAsText\n        minz = parameters[8].valueAsText\n        maxz = parameters[9].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_idw_interpolation(i=i, output=output, parameter=parameter, returns=returns, resolution=resolution, weight=weight, radius=radius, exclude_cls=exclude_cls, minz=minz, maxz=maxz)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarInfo(object):\n    def __init__(self):\n        self.label = \"Lidar Info\"\n        self.description = \"Prints information about a LiDAR (LAS) dataset, including header, point return frequency, and classification data and information about the variable length records (VLRs) and geokeys.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Summary Report File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        density = arcpy.Parameter(\n            displayName=\"Calculate the average point density and nominal point spacing?\",\n            name=\"density\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        density.value = 'True'\n\n        vlr = arcpy.Parameter(\n            displayName=\"Print the variable length records (VLRs)?\",\n            name=\"vlr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        vlr.value = 'True'\n\n        geokeys = arcpy.Parameter(\n            displayName=\"Print the geokeys?\",\n            name=\"geokeys\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        geokeys.value = 'True'\n\n        params = [i, output, density, vlr, geokeys]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        density = parameters[2].valueAsText\n        vlr = parameters[3].valueAsText\n        geokeys = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_info(i=i, output=output, density=density, vlr=vlr, geokeys=geokeys)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarJoin(object):\n    def __init__(self):\n        self.label = \"Lidar Join\"\n        self.description = \"Joins multiple LiDAR (LAS) files into a single LAS file.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input LiDAR Files\",\n            name=\"inputs\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n        inputs.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_join(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarKappaIndex(object):\n    def __init__(self):\n        self.label = \"Lidar Kappa Index\"\n        self.description = \"Performs a kappa index of agreement (KIA) analysis on the classifications of two LAS files.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input LiDAR File (Classification)\",\n            name=\"input1\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        input1.filter.list = [\"las\", \"zip\"]\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input LiDAR File (Reference)\",\n            name=\"input2\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        input2.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        class_accuracy = arcpy.Parameter(\n            displayName=\"Output Class Accuracy Raster File\",\n            name=\"class_accuracy\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        class_accuracy.filter.list = [\"tif\"]\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        params = [input1, input2, output, class_accuracy, resolution]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        input2 = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        class_accuracy = parameters[3].valueAsText\n        resolution = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_kappa_index(input1=input1, input2=input2, output=output, class_accuracy=class_accuracy, resolution=resolution)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarNearestNeighbourGridding(object):\n    def __init__(self):\n        self.label = \"Lidar Nearest Neighbour Gridding\"\n        self.description = \"Grids LiDAR files using nearest-neighbour scheme. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        parameter = arcpy.Parameter(\n            displayName=\"Interpolation Parameter\",\n            name=\"parameter\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        parameter.filter.type = \"ValueList\"\n        parameter.filter.list = ['elevation', 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data', 'time']\n        parameter.value = 'elevation'\n\n        returns = arcpy.Parameter(\n            displayName=\"Point Returns Included\",\n            name=\"returns\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        returns.filter.type = \"ValueList\"\n        returns.filter.list = ['all', 'last', 'first']\n        returns.value = 'all'\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '2.5'\n\n        exclude_cls = arcpy.Parameter(\n            displayName=\"Exclusion Classes (0-18, based on LAS spec; e.g. 3,4,5,6,7)\",\n            name=\"exclude_cls\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        minz = arcpy.Parameter(\n            displayName=\"Minimum Elevation Value (optional)\",\n            name=\"minz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        maxz = arcpy.Parameter(\n            displayName=\"Maximum Elevation Value (optional)\",\n            name=\"maxz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, parameter, returns, resolution, radius, exclude_cls, minz, maxz]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        parameter = parameters[2].valueAsText\n        returns = parameters[3].valueAsText\n        resolution = parameters[4].valueAsText\n        radius = parameters[5].valueAsText\n        exclude_cls = parameters[6].valueAsText\n        minz = parameters[7].valueAsText\n        maxz = parameters[8].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_nearest_neighbour_gridding(i=i, output=output, parameter=parameter, returns=returns, resolution=resolution, radius=radius, exclude_cls=exclude_cls, minz=minz, maxz=maxz)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarPointDensity(object):\n    def __init__(self):\n        self.label = \"Lidar Point Density\"\n        self.description = \"Calculates the spatial pattern of point density for a LiDAR data set. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        returns = arcpy.Parameter(\n            displayName=\"Point Returns Included\",\n            name=\"returns\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        returns.filter.type = \"ValueList\"\n        returns.filter.list = ['all', 'last', 'first']\n        returns.value = 'all'\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '2.5'\n\n        exclude_cls = arcpy.Parameter(\n            displayName=\"Exclusion Classes (0-18, based on LAS spec; e.g. 3,4,5,6,7)\",\n            name=\"exclude_cls\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        minz = arcpy.Parameter(\n            displayName=\"Minimum Elevation Value (optional)\",\n            name=\"minz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        maxz = arcpy.Parameter(\n            displayName=\"Maximum Elevation Value (optional)\",\n            name=\"maxz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, returns, resolution, radius, exclude_cls, minz, maxz]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        returns = parameters[2].valueAsText\n        resolution = parameters[3].valueAsText\n        radius = parameters[4].valueAsText\n        exclude_cls = parameters[5].valueAsText\n        minz = parameters[6].valueAsText\n        maxz = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_point_density(i=i, output=output, returns=returns, resolution=resolution, radius=radius, exclude_cls=exclude_cls, minz=minz, maxz=maxz)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarPointReturnAnalysis(object):\n    def __init__(self):\n        self.label = \"Lidar Point Return Analysis\"\n        self.description = \"This tool performs a quality control check on the return values of points in a LiDAR file.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR Points\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_point_return_analysis(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarPointStats(object):\n    def __init__(self):\n        self.label = \"Lidar Point Stats\"\n        self.description = \"Creates several rasters summarizing the distribution of LAS point data. When the input/output parameters are not specified, the tool works on all LAS files contained within the working directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        num_points = arcpy.Parameter(\n            displayName=\"Output number of points?\",\n            name=\"num_points\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_points.value = 'True'\n\n        num_pulses = arcpy.Parameter(\n            displayName=\"Output number of pulses?\",\n            name=\"num_pulses\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        avg_points_per_pulse = arcpy.Parameter(\n            displayName=\"Output average number of points per pulse?\",\n            name=\"avg_points_per_pulse\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        avg_points_per_pulse.value = 'True'\n\n        z_range = arcpy.Parameter(\n            displayName=\"Output elevation range?\",\n            name=\"z_range\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        intensity_range = arcpy.Parameter(\n            displayName=\"Output intensity range?\",\n            name=\"intensity_range\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        predom_class = arcpy.Parameter(\n            displayName=\"Output predominant class?\",\n            name=\"predom_class\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, resolution, num_points, num_pulses, avg_points_per_pulse, z_range, intensity_range, predom_class]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        resolution = parameters[1].valueAsText\n        num_points = parameters[2].valueAsText\n        num_pulses = parameters[3].valueAsText\n        avg_points_per_pulse = parameters[4].valueAsText\n        z_range = parameters[5].valueAsText\n        intensity_range = parameters[6].valueAsText\n        predom_class = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_point_stats(i=i, resolution=resolution, num_points=num_points, num_pulses=num_pulses, avg_points_per_pulse=avg_points_per_pulse, z_range=z_range, intensity_range=intensity_range, predom_class=predom_class)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarRansacPlanes(object):\n    def __init__(self):\n        self.label = \"Lidar Ransac Planes\"\n        self.description = \"Performs a RANSAC analysis to identify points within a LiDAR point cloud that belong to linear planes.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '2.0'\n\n        num_iter = arcpy.Parameter(\n            displayName=\"Number of Iterations\",\n            name=\"num_iter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_iter.value = '50'\n\n        num_samples = arcpy.Parameter(\n            displayName=\"Number of Sample Points\",\n            name=\"num_samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_samples.value = '5'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Inlier Threshold\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        threshold.value = '0.35'\n\n        model_size = arcpy.Parameter(\n            displayName=\"Acceptable Model Size\",\n            name=\"model_size\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        model_size.value = '8'\n\n        max_slope = arcpy.Parameter(\n            displayName=\"Maximum Planar Slope\",\n            name=\"max_slope\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_slope.value = '80.0'\n\n        classify = arcpy.Parameter(\n            displayName=\"Classify Points\",\n            name=\"classify\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        classify.value = 'False'\n\n        last_returns = arcpy.Parameter(\n            displayName=\"Last Returns Only\",\n            name=\"last_returns\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        last_returns.value = 'False'\n\n        params = [i, output, radius, num_iter, num_samples, threshold, model_size, max_slope, classify, last_returns]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        radius = parameters[2].valueAsText\n        num_iter = parameters[3].valueAsText\n        num_samples = parameters[4].valueAsText\n        threshold = parameters[5].valueAsText\n        model_size = parameters[6].valueAsText\n        max_slope = parameters[7].valueAsText\n        classify = parameters[8].valueAsText\n        last_returns = parameters[9].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_ransac_planes(i=i, output=output, radius=radius, num_iter=num_iter, num_samples=num_samples, threshold=threshold, model_size=model_size, max_slope=max_slope, classify=classify, last_returns=last_returns)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarRbfInterpolation(object):\n    def __init__(self):\n        self.label = \"Lidar Rbf Interpolation\"\n        self.description = \"Interpolates LAS files using a radial basis function (RBF) scheme. When the input/output parameters are not specified, the tool interpolates all LAS files contained within the working directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        parameter = arcpy.Parameter(\n            displayName=\"Interpolation Parameter\",\n            name=\"parameter\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        parameter.filter.type = \"ValueList\"\n        parameter.filter.list = ['elevation', 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data']\n        parameter.value = 'elevation'\n\n        returns = arcpy.Parameter(\n            displayName=\"Point Returns Included\",\n            name=\"returns\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        returns.filter.type = \"ValueList\"\n        returns.filter.list = ['all', 'last', 'first']\n        returns.value = 'all'\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        num_points = arcpy.Parameter(\n            displayName=\"Number of Points\",\n            name=\"num_points\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_points.value = '20'\n\n        exclude_cls = arcpy.Parameter(\n            displayName=\"Exclusion Classes (0-18, based on LAS spec; e.g. 3,4,5,6,7)\",\n            name=\"exclude_cls\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        minz = arcpy.Parameter(\n            displayName=\"Minimum Elevation Value (optional)\",\n            name=\"minz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        maxz = arcpy.Parameter(\n            displayName=\"Maximum Elevation Value (optional)\",\n            name=\"maxz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        func_type = arcpy.Parameter(\n            displayName=\"Radial Basis Function Type\",\n            name=\"func_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        func_type.filter.type = \"ValueList\"\n        func_type.filter.list = ['ThinPlateSpline', 'PolyHarmonic', 'Gaussian', 'MultiQuadric', 'InverseMultiQuadric']\n        func_type.value = 'ThinPlateSpline'\n\n        poly_order = arcpy.Parameter(\n            displayName=\"Polynomial Order\",\n            name=\"poly_order\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        poly_order.filter.type = \"ValueList\"\n        poly_order.filter.list = ['none', 'constant', 'affine']\n        poly_order.value = 'none'\n\n        weight = arcpy.Parameter(\n            displayName=\"Weight\",\n            name=\"weight\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        weight.value = '5'\n\n        params = [i, output, parameter, returns, resolution, num_points, exclude_cls, minz, maxz, func_type, poly_order, weight]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        parameter = parameters[2].valueAsText\n        returns = parameters[3].valueAsText\n        resolution = parameters[4].valueAsText\n        num_points = parameters[5].valueAsText\n        exclude_cls = parameters[6].valueAsText\n        minz = parameters[7].valueAsText\n        maxz = parameters[8].valueAsText\n        func_type = parameters[9].valueAsText\n        poly_order = parameters[10].valueAsText\n        weight = parameters[11].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_rbf_interpolation(i=i, output=output, parameter=parameter, returns=returns, resolution=resolution, num_points=num_points, exclude_cls=exclude_cls, minz=minz, maxz=maxz, func_type=func_type, poly_order=poly_order, weight=weight)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarRemoveDuplicates(object):\n    def __init__(self):\n        self.label = \"Lidar Remove Duplicates\"\n        self.description = \"Removes duplicate points from a LiDAR data set.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        include_z = arcpy.Parameter(\n            displayName=\"Include z-values in point comparison?\",\n            name=\"include_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        include_z.value = 'False'\n\n        params = [i, output, include_z]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        include_z = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_remove_duplicates(i=i, output=output, include_z=include_z)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarRemoveOutliers(object):\n    def __init__(self):\n        self.label = \"Lidar Remove Outliers\"\n        self.description = \"Removes outliers (high and low points) in a LiDAR point cloud.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '2.0'\n\n        elev_diff = arcpy.Parameter(\n            displayName=\"Max. Elevation Difference\",\n            name=\"elev_diff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        elev_diff.value = '50.0'\n\n        use_median = arcpy.Parameter(\n            displayName=\"Use difference from median elevation?\",\n            name=\"use_median\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        classify = arcpy.Parameter(\n            displayName=\"Classify Points\",\n            name=\"classify\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        classify.value = 'True'\n\n        params = [i, output, radius, elev_diff, use_median, classify]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        radius = parameters[2].valueAsText\n        elev_diff = parameters[3].valueAsText\n        use_median = parameters[4].valueAsText\n        classify = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_remove_outliers(i=i, output=output, radius=radius, elev_diff=elev_diff, use_median=use_median, classify=classify)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarRooftopAnalysis(object):\n    def __init__(self):\n        self.label = \"Lidar Rooftop Analysis\"\n        self.description = \"Identifies roof segments in a LiDAR point cloud.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        buildings = arcpy.Parameter(\n            displayName=\"Input Building Footprint Polygon File\",\n            name=\"buildings\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        buildings.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '2.0'\n\n        num_iter = arcpy.Parameter(\n            displayName=\"Number of Iterations\",\n            name=\"num_iter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_iter.value = '50'\n\n        num_samples = arcpy.Parameter(\n            displayName=\"Number of Sample Points\",\n            name=\"num_samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_samples.value = '10'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Inlier Threshold\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        threshold.value = '0.15'\n\n        model_size = arcpy.Parameter(\n            displayName=\"Acceptable Model Size (points)\",\n            name=\"model_size\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        model_size.value = '15'\n\n        max_slope = arcpy.Parameter(\n            displayName=\"Maximum Planar Slope (degrees)\",\n            name=\"max_slope\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_slope.value = '65.0'\n\n        norm_diff = arcpy.Parameter(\n            displayName=\"Normal Difference Threshold (degrees)\",\n            name=\"norm_diff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        norm_diff.value = '10.0'\n\n        azimuth = arcpy.Parameter(\n            displayName=\"Azimuth (degrees)\",\n            name=\"azimuth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        azimuth.value = '180.0'\n\n        altitude = arcpy.Parameter(\n            displayName=\"Altitude (degrees)\",\n            name=\"altitude\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        altitude.value = '30.0'\n\n        params = [i, buildings, output, radius, num_iter, num_samples, threshold, model_size, max_slope, norm_diff, azimuth, altitude]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        buildings = parameters[1].valueAsText\n        if buildings is not None:\n            desc = arcpy.Describe(buildings)\n            buildings = desc.catalogPath\n        output = parameters[2].valueAsText\n        radius = parameters[3].valueAsText\n        num_iter = parameters[4].valueAsText\n        num_samples = parameters[5].valueAsText\n        threshold = parameters[6].valueAsText\n        model_size = parameters[7].valueAsText\n        max_slope = parameters[8].valueAsText\n        norm_diff = parameters[9].valueAsText\n        azimuth = parameters[10].valueAsText\n        altitude = parameters[11].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_rooftop_analysis(i=i, buildings=buildings, output=output, radius=radius, num_iter=num_iter, num_samples=num_samples, threshold=threshold, model_size=model_size, max_slope=max_slope, norm_diff=norm_diff, azimuth=azimuth, altitude=altitude)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarSegmentation(object):\n    def __init__(self):\n        self.label = \"Lidar Segmentation\"\n        self.description = \"Segments a LiDAR point cloud based on differences in the orientation of fitted planar surfaces and point proximity.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '2.0'\n\n        num_iter = arcpy.Parameter(\n            displayName=\"Number of Iterations\",\n            name=\"num_iter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_iter.value = '50'\n\n        num_samples = arcpy.Parameter(\n            displayName=\"Number of Sample Points\",\n            name=\"num_samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_samples.value = '10'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Inlier Threshold\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        threshold.value = '0.15'\n\n        model_size = arcpy.Parameter(\n            displayName=\"Acceptable Model Size\",\n            name=\"model_size\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        model_size.value = '15'\n\n        max_slope = arcpy.Parameter(\n            displayName=\"Maximum Planar Slope\",\n            name=\"max_slope\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_slope.value = '80.0'\n\n        norm_diff = arcpy.Parameter(\n            displayName=\"Normal Difference Threshold\",\n            name=\"norm_diff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        norm_diff.value = '10.0'\n\n        maxzdiff = arcpy.Parameter(\n            displayName=\"Maximum Elevation Difference Between Points\",\n            name=\"maxzdiff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        maxzdiff.value = '1.0'\n\n        classes = arcpy.Parameter(\n            displayName=\"Don't cross class boundaries?\",\n            name=\"classes\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        classes.value = 'False'\n\n        ground = arcpy.Parameter(\n            displayName=\"Classify largest segment as ground?\",\n            name=\"ground\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        ground.value = 'False'\n\n        params = [i, output, radius, num_iter, num_samples, threshold, model_size, max_slope, norm_diff, maxzdiff, classes, ground]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        radius = parameters[2].valueAsText\n        num_iter = parameters[3].valueAsText\n        num_samples = parameters[4].valueAsText\n        threshold = parameters[5].valueAsText\n        model_size = parameters[6].valueAsText\n        max_slope = parameters[7].valueAsText\n        norm_diff = parameters[8].valueAsText\n        maxzdiff = parameters[9].valueAsText\n        classes = parameters[10].valueAsText\n        ground = parameters[11].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_segmentation(i=i, output=output, radius=radius, num_iter=num_iter, num_samples=num_samples, threshold=threshold, model_size=model_size, max_slope=max_slope, norm_diff=norm_diff, maxzdiff=maxzdiff, classes=classes, ground=ground)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarSegmentationBasedFilter(object):\n    def __init__(self):\n        self.label = \"Lidar Segmentation Based Filter\"\n        self.description = \"Identifies ground points within LiDAR point clouds using a segmentation based approach.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        radius.value = '5.0'\n\n        norm_diff = arcpy.Parameter(\n            displayName=\"Normal Difference Threshold\",\n            name=\"norm_diff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        norm_diff.value = '2.0'\n\n        maxzdiff = arcpy.Parameter(\n            displayName=\"Maximum Elevation Difference Between Points\",\n            name=\"maxzdiff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        maxzdiff.value = '1.0'\n\n        classify = arcpy.Parameter(\n            displayName=\"Classify Points\",\n            name=\"classify\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, radius, norm_diff, maxzdiff, classify]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        radius = parameters[2].valueAsText\n        norm_diff = parameters[3].valueAsText\n        maxzdiff = parameters[4].valueAsText\n        classify = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_segmentation_based_filter(i=i, output=output, radius=radius, norm_diff=norm_diff, maxzdiff=maxzdiff, classify=classify)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarShift(object):\n    def __init__(self):\n        self.label = \"Lidar Shift\"\n        self.description = \"Shifts the x,y,z coordinates of a LiDAR file.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR Points\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        x_shift = arcpy.Parameter(\n            displayName=\"x-shift\",\n            name=\"x_shift\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        y_shift = arcpy.Parameter(\n            displayName=\"y-shift\",\n            name=\"y_shift\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        z_shift = arcpy.Parameter(\n            displayName=\"z-shift\",\n            name=\"z_shift\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        params = [i, output, x_shift, y_shift, z_shift]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        x_shift = parameters[2].valueAsText\n        y_shift = parameters[3].valueAsText\n        z_shift = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_shift(i=i, output=output, x_shift=x_shift, y_shift=y_shift, z_shift=z_shift)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarSibsonInterpolation(object):\n    def __init__(self):\n        self.label = \"Lidar Sibson Interpolation\"\n        self.description = \"This tool interpolates one or more LiDAR tiles using Sibson's natural neighbour method.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        parameter = arcpy.Parameter(\n            displayName=\"Interpolation Parameter\",\n            name=\"parameter\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        parameter.filter.type = \"ValueList\"\n        parameter.filter.list = ['elevation', 'intensity', 'class', 'return_number', 'number_of_returns', 'scan_angle', 'user_data']\n        parameter.value = 'elevation'\n\n        returns = arcpy.Parameter(\n            displayName=\"Point Returns Included\",\n            name=\"returns\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        returns.filter.type = \"ValueList\"\n        returns.filter.list = ['all', 'last', 'first']\n        returns.value = 'all'\n\n        resolution = arcpy.Parameter(\n            displayName=\"Output Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        exclude_cls = arcpy.Parameter(\n            displayName=\"Exclusion Classes (0-18, based on LAS spec; e.g. 3,4,5,6,7)\",\n            name=\"exclude_cls\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        minz = arcpy.Parameter(\n            displayName=\"Minimum Elevation Value (optional)\",\n            name=\"minz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        maxz = arcpy.Parameter(\n            displayName=\"Maximum Elevation Value (optional)\",\n            name=\"maxz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, parameter, returns, resolution, exclude_cls, minz, maxz]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        parameter = parameters[2].valueAsText\n        returns = parameters[3].valueAsText\n        resolution = parameters[4].valueAsText\n        exclude_cls = parameters[5].valueAsText\n        minz = parameters[6].valueAsText\n        maxz = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_sibson_interpolation(i=i, output=output, parameter=parameter, returns=returns, resolution=resolution, exclude_cls=exclude_cls, minz=minz, maxz=maxz)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarTinGridding(object):\n    def __init__(self):\n        self.label = \"Lidar Tin Gridding\"\n        self.description = \"Creates a raster grid based on a Delaunay triangular irregular network (TIN) fitted to LiDAR points.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        parameter = arcpy.Parameter(\n            displayName=\"Interpolation Parameter\",\n            name=\"parameter\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        parameter.filter.type = \"ValueList\"\n        parameter.filter.list = ['elevation', 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data']\n        parameter.value = 'elevation'\n\n        returns = arcpy.Parameter(\n            displayName=\"Point Returns Included\",\n            name=\"returns\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        returns.filter.type = \"ValueList\"\n        returns.filter.list = ['all', 'last', 'first']\n        returns.value = 'all'\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        exclude_cls = arcpy.Parameter(\n            displayName=\"Exclusion Classes (0-18, based on LAS spec; e.g. 3,4,5,6,7)\",\n            name=\"exclude_cls\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        exclude_cls.value = '7,18'\n\n        minz = arcpy.Parameter(\n            displayName=\"Minimum Elevation Value (optional)\",\n            name=\"minz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        maxz = arcpy.Parameter(\n            displayName=\"Maximum Elevation Value (optional)\",\n            name=\"maxz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_triangle_edge_length = arcpy.Parameter(\n            displayName=\"Maximum Triangle Edge Length (optional)\",\n            name=\"max_triangle_edge_length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, parameter, returns, resolution, exclude_cls, minz, maxz, max_triangle_edge_length]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        parameter = parameters[2].valueAsText\n        returns = parameters[3].valueAsText\n        resolution = parameters[4].valueAsText\n        exclude_cls = parameters[5].valueAsText\n        minz = parameters[6].valueAsText\n        maxz = parameters[7].valueAsText\n        max_triangle_edge_length = parameters[8].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_tin_gridding(i=i, output=output, parameter=parameter, returns=returns, resolution=resolution, exclude_cls=exclude_cls, minz=minz, maxz=maxz, max_triangle_edge_length=max_triangle_edge_length)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarThin(object):\n    def __init__(self):\n        self.label = \"Lidar Thin\"\n        self.description = \"Thins a LiDAR point cloud, reducing point density.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        resolution = arcpy.Parameter(\n            displayName=\"Sample Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '2.0'\n\n        method = arcpy.Parameter(\n            displayName=\"Point Selection Method\",\n            name=\"method\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        method.filter.type = \"ValueList\"\n        method.filter.list = ['first', 'last', 'lowest', 'highest', 'nearest']\n        method.value = 'lowest'\n\n        save_filtered = arcpy.Parameter(\n            displayName=\"Save filtered points to separate file?\",\n            name=\"save_filtered\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        save_filtered.value = 'False'\n\n        params = [i, output, resolution, method, save_filtered]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        resolution = parameters[2].valueAsText\n        method = parameters[3].valueAsText\n        save_filtered = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_thin(i=i, output=output, resolution=resolution, method=method, save_filtered=save_filtered)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarThinHighDensity(object):\n    def __init__(self):\n        self.label = \"Lidar Thin High Density\"\n        self.description = \"Thins points from high density areas within a LiDAR point cloud.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        density = arcpy.Parameter(\n            displayName=\"Max. Point Density (pts/m^2)\",\n            name=\"density\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        save_filtered = arcpy.Parameter(\n            displayName=\"Save filtered points to separate file?\",\n            name=\"save_filtered\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        save_filtered.value = 'False'\n\n        params = [i, output, resolution, density, save_filtered]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        resolution = parameters[2].valueAsText\n        density = parameters[3].valueAsText\n        save_filtered = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_thin_high_density(i=i, output=output, resolution=resolution, density=density, save_filtered=save_filtered)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarTile(object):\n    def __init__(self):\n        self.label = \"Lidar Tile\"\n        self.description = \"Tiles a LiDAR LAS file into multiple LAS files.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        width = arcpy.Parameter(\n            displayName=\"Tile Width\",\n            name=\"width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        width.value = '1000.0'\n\n        height = arcpy.Parameter(\n            displayName=\"Tile Height\",\n            name=\"height\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        height.value = '1000.0'\n\n        origin_x = arcpy.Parameter(\n            displayName=\"Origin Point X-Coordinate\",\n            name=\"origin_x\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        origin_x.value = '0.0'\n\n        origin_y = arcpy.Parameter(\n            displayName=\"Origin Point Y-Coordinate\",\n            name=\"origin_y\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        origin_y.value = '0.0'\n\n        min_points = arcpy.Parameter(\n            displayName=\"Minimum Number of Tile Points\",\n            name=\"min_points\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_points.value = '2'\n\n        params = [i, width, height, origin_x, origin_y, min_points]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        width = parameters[1].valueAsText\n        height = parameters[2].valueAsText\n        origin_x = parameters[3].valueAsText\n        origin_y = parameters[4].valueAsText\n        min_points = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_tile(i=i, width=width, height=height, origin_x=origin_x, origin_y=origin_y, min_points=min_points)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarTileFootprint(object):\n    def __init__(self):\n        self.label = \"Lidar Tile Footprint\"\n        self.description = \"Creates a vector polygon of the convex hull of a LiDAR point cloud. When the input/output parameters are not specified, the tool works with all LAS files contained within the working directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        hull = arcpy.Parameter(\n            displayName=\"Create Convex Hull Around Points\",\n            name=\"hull\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        hull.value = 'False'\n\n        params = [i, output, hull]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        hull = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_tile_footprint(i=i, output=output, hull=hull)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarTophatTransform(object):\n    def __init__(self):\n        self.label = \"Lidar Tophat Transform\"\n        self.description = \"Performs a white top-hat transform on a Lidar dataset; as an estimate of height above ground, this is useful for modelling the vegetation canopy.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        radius.value = '1.0'\n\n        params = [i, output, radius]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        radius = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_tophat_transform(i=i, output=output, radius=radius)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LineDetectionFilter(object):\n    def __init__(self):\n        self.label = \"Line Detection Filter\"\n        self.description = \"Performs a line-detection filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        variant = arcpy.Parameter(\n            displayName=\"Variant\",\n            name=\"variant\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        variant.filter.type = \"ValueList\"\n        variant.filter.list = ['vertical', 'horizontal', '45', '135']\n        variant.value = 'vertical'\n\n        absvals = arcpy.Parameter(\n            displayName=\"Output absolute values?\",\n            name=\"absvals\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        clip = arcpy.Parameter(\n            displayName=\"Distribution Tail Clip Amount (%)\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '0.0'\n\n        params = [i, output, variant, absvals, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        variant = parameters[2].valueAsText\n        absvals = parameters[3].valueAsText\n        clip = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.line_detection_filter(i=i, output=output, variant=variant, absvals=absvals, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LineIntersections(object):\n    def __init__(self):\n        self.label = \"Line Intersections\"\n        self.description = \"Identifies points where the features of two vector line layers intersect.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input Vector Lines File\",\n            name=\"input1\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        input1.filter.list = [\"Polyline\", \"Polygon\"]\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input Vector Lines File\",\n            name=\"input2\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        input2.filter.list = [\"Polyline\", \"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector Point File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.line_intersections(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LineThinning(object):\n    def __init__(self):\n        self.label = \"Line Thinning\"\n        self.description = \"Performs line thinning a on Boolean raster image; intended to be used with the RemoveSpurs tool.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.line_thinning(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LinearityIndex(object):\n    def __init__(self):\n        self.label = \"Linearity Index\"\n        self.description = \"Calculates the linearity index for vector polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.linearity_index(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LinesToPolygons(object):\n    def __init__(self):\n        self.label = \"Lines To Polygons\"\n        self.description = \"Converts vector polylines to polygons.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Line File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lines_to_polygons(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ListUniqueValues(object):\n    def __init__(self):\n        self.label = \"List Unique Values\"\n        self.description = \"Lists the unique values contained in a field within a vector's attribute table.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [i, field, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.list_unique_values(i=i, field=field, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ListUniqueValuesRaster(object):\n    def __init__(self):\n        self.label = \"List Unique Values Raster\"\n        self.description = \"Lists the unique values contained in a field within a vector's attribute table.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.list_unique_values_raster(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Ln(object):\n    def __init__(self):\n        self.label = \"Ln\"\n        self.description = \"Returns the natural logarithm of values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.ln(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LocalHypsometricAnalysis(object):\n    def __init__(self):\n        self.label = \"Local Hypsometric Analysis\"\n        self.description = \"This tool calculates a local, neighbourhood-based hypsometric integral raster.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_mag = arcpy.Parameter(\n            displayName=\"Output Magnitude Raster\",\n            name=\"out_mag\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_mag.filter.list = [\"tif\"]\n\n        out_scale = arcpy.Parameter(\n            displayName=\"Output Scale Raster\",\n            name=\"out_scale\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_scale.filter.list = [\"tif\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_scale.value = '4'\n\n        step = arcpy.Parameter(\n            displayName=\"Base Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step.value = '1'\n\n        num_steps = arcpy.Parameter(\n            displayName=\"Number of Steps\",\n            name=\"num_steps\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_steps.value = '10'\n\n        step_nonlinearity = arcpy.Parameter(\n            displayName=\"Step Nonlinearity\",\n            name=\"step_nonlinearity\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step_nonlinearity.value = '1.0'\n\n        params = [i, out_mag, out_scale, min_scale, step, num_steps, step_nonlinearity]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        out_mag = parameters[1].valueAsText\n        out_scale = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        step = parameters[4].valueAsText\n        num_steps = parameters[5].valueAsText\n        step_nonlinearity = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.local_hypsometric_analysis(i=i, out_mag=out_mag, out_scale=out_scale, min_scale=min_scale, step=step, num_steps=num_steps, step_nonlinearity=step_nonlinearity)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LocalQuadraticRegression(object):\n    def __init__(self):\n        self.label = \"Local Quadratic Regression\"\n        self.description = \"An implementation of the constrained quadratic regression algorithm using a flexible window size described in Wood (1996).\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Edge Length\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '3'\n\n        params = [dem, output, filter]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.local_quadratic_regression(dem=dem, output=output, filter=filter)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Log10(object):\n    def __init__(self):\n        self.label = \"Log10\"\n        self.description = \"Returns the base-10 logarithm of values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.log10(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Log2(object):\n    def __init__(self):\n        self.label = \"Log2\"\n        self.description = \"Returns the base-2 logarithm of values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.log2(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LogisticRegression(object):\n    def __init__(self):\n        self.label = \"Logistic Regression\"\n        self.description = \"Performs a logistic regression analysis using training site polygons/points and predictor rasters.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Predictor Rasters\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        scaling = arcpy.Parameter(\n            displayName=\"Scaling Method\",\n            name=\"scaling\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        scaling.filter.type = \"ValueList\"\n        scaling.filter.list = ['None', 'Normalize', 'Standardize']\n        scaling.value = 'Normalize'\n\n        training = arcpy.Parameter(\n            displayName=\"Input Training Polygons/Points\",\n            name=\"training\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        field = arcpy.Parameter(\n            displayName=\"Class Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [training.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        test_proportion = arcpy.Parameter(\n            displayName=\"Test Proportion\",\n            name=\"test_proportion\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        test_proportion.value = '0.2'\n\n        params = [inputs, scaling, training, field, output, test_proportion]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        scaling = parameters[1].valueAsText\n        training = parameters[2].valueAsText\n        if training is not None:\n            desc = arcpy.Describe(training)\n            training = desc.catalogPath\n        field = parameters[3].valueAsText\n        output = parameters[4].valueAsText\n        test_proportion = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.logistic_regression(inputs=inputs, scaling=scaling, training=training, field=field, output=output, test_proportion=test_proportion)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LongProfile(object):\n    def __init__(self):\n        self.label = \"Long Profile\"\n        self.description = \"Plots the stream longitudinal profiles for one or more rivers.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, streams, dem, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        dem = parameters[2].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[3].valueAsText\n        esri_pntr = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.long_profile(d8_pntr=d8_pntr, streams=streams, dem=dem, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LongProfileFromPoints(object):\n    def __init__(self):\n        self.label = \"Long Profile From Points\"\n        self.description = \"Plots the longitudinal profiles from flow-paths initiating from a set of vector points.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        points = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"points\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        points.filter.list = [\"Point\"]\n\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, points, dem, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        points = parameters[1].valueAsText\n        if points is not None:\n            desc = arcpy.Describe(points)\n            points = desc.catalogPath\n        dem = parameters[2].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[3].valueAsText\n        esri_pntr = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.long_profile_from_points(d8_pntr=d8_pntr, points=points, dem=dem, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LongestFlowpath(object):\n    def __init__(self):\n        self.label = \"Longest Flowpath\"\n        self.description = \"Delineates the longest flowpaths for a group of subbasins or watersheds.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        basins = arcpy.Parameter(\n            displayName=\"Basins File\",\n            name=\"basins\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [dem, basins, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        basins = parameters[1].valueAsText\n        if basins is not None:\n            desc = arcpy.Describe(basins)\n            basins = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.longest_flowpath(dem=dem, basins=basins, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LowPointsOnHeadwaterDivides(object):\n    def __init__(self):\n        self.label = \"Low Points On Headwater Divides\"\n        self.description = \"This tool locates saddle points along ridges within a digital elevation model (DEM)\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams Raster\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [dem, streams, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.low_points_on_headwater_divides(dem=dem, streams=streams, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LowestPosition(object):\n    def __init__(self):\n        self.label = \"Lowest Position\"\n        self.description = \"Identifies the stack position of the minimum value within a raster stack on a cell-by-cell basis.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lowest_position(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MdInfFlowAccumulation(object):\n    def __init__(self):\n        self.label = \"Md Inf Flow Accumulation\"\n        self.description = \"Calculates an FD8 flow accumulation raster from an input DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['cells', 'specific contributing area', 'catchment area']\n        out_type.value = 'specific contributing area'\n\n        exponent = arcpy.Parameter(\n            displayName=\"Exponent Parameter\",\n            name=\"exponent\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        exponent.value = '1.1'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Convergence Threshold (grid cells; blank for none)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip the upper tail by 1%?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, out_type, exponent, threshold, log, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_type = parameters[2].valueAsText\n        exponent = parameters[3].valueAsText\n        threshold = parameters[4].valueAsText\n        log = parameters[5].valueAsText\n        clip = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.md_inf_flow_accumulation(dem=dem, output=output, out_type=out_type, exponent=exponent, threshold=threshold, log=log, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MajorityFilter(object):\n    def __init__(self):\n        self.label = \"Majority Filter\"\n        self.description = \"Assigns each cell in the output grid the most frequently occurring value (mode) in a moving window centred on each grid cell in the input raster.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.majority_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MapOffTerrainObjects(object):\n    def __init__(self):\n        self.label = \"Map Off Terrain Objects\"\n        self.description = \"Maps off-terrain objects in a digital elevation model (DEM).\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        max_slope = arcpy.Parameter(\n            displayName=\"Maximum Slope\",\n            name=\"max_slope\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        max_slope.value = '40.0'\n\n        min_size = arcpy.Parameter(\n            displayName=\"Minimum Feature Size\",\n            name=\"min_size\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        min_size.value = '1'\n\n        params = [dem, output, max_slope, min_size]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        max_slope = parameters[2].valueAsText\n        min_size = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.map_off_terrain_objects(dem=dem, output=output, max_slope=max_slope, min_size=min_size)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Max(object):\n    def __init__(self):\n        self.label = \"Max\"\n        self.description = \"Performs a MAX operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxAbsoluteOverlay(object):\n    def __init__(self):\n        self.label = \"Max Absolute Overlay\"\n        self.description = \"Evaluates the maximum absolute value for each grid cell from a stack of input rasters.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_absolute_overlay(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxAnisotropyDev(object):\n    def __init__(self):\n        self.label = \"Max Anisotropy Dev\"\n        self.description = \"Calculates the maximum anisotropy (directionality) in elevation deviation over a range of spatial scales.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_mag = arcpy.Parameter(\n            displayName=\"Output DEVmax Magnitude File\",\n            name=\"out_mag\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_mag.filter.list = [\"tif\"]\n\n        out_scale = arcpy.Parameter(\n            displayName=\"Output DEVmax Scale File\",\n            name=\"out_scale\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_scale.filter.list = [\"tif\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        min_scale.value = '3'\n\n        max_scale = arcpy.Parameter(\n            displayName=\"Maximum Search Neighbourhood Radius (grid cells)\",\n            name=\"max_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        step = arcpy.Parameter(\n            displayName=\"Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        step.value = '2'\n\n        params = [dem, out_mag, out_scale, min_scale, max_scale, step]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        out_mag = parameters[1].valueAsText\n        out_scale = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        max_scale = parameters[4].valueAsText\n        step = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_anisotropy_dev(dem=dem, out_mag=out_mag, out_scale=out_scale, min_scale=min_scale, max_scale=max_scale, step=step)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxAnisotropyDevSignature(object):\n    def __init__(self):\n        self.label = \"Max Anisotropy Dev Signature\"\n        self.description = \"Calculates the anisotropy in deviation from mean for points over a range of spatial scales.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        points = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"points\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        points.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_scale.value = '1'\n\n        max_scale = arcpy.Parameter(\n            displayName=\"Maximum Search Neighbourhood Radius (grid cells)\",\n            name=\"max_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        step = arcpy.Parameter(\n            displayName=\"Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step.value = '1'\n\n        params = [dem, points, output, min_scale, max_scale, step]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        points = parameters[1].valueAsText\n        if points is not None:\n            desc = arcpy.Describe(points)\n            points = desc.catalogPath\n        output = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        max_scale = parameters[4].valueAsText\n        step = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_anisotropy_dev_signature(dem=dem, points=points, output=output, min_scale=min_scale, max_scale=max_scale, step=step)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxBranchLength(object):\n    def __init__(self):\n        self.label = \"Max Branch Length\"\n        self.description = \"Lindsay and Seibert's (2013) branch length index is used to map drainage divides or ridge lines.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, log]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_branch_length(dem=dem, output=output, log=log)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxDifferenceFromMean(object):\n    def __init__(self):\n        self.label = \"Max Difference From Mean\"\n        self.description = \"Calculates the maximum difference from mean elevation over a range of spatial scales.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_mag = arcpy.Parameter(\n            displayName=\"Output DIFFmax Magnitude File\",\n            name=\"out_mag\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_mag.filter.list = [\"tif\"]\n\n        out_scale = arcpy.Parameter(\n            displayName=\"Output DIFFmax Scale File\",\n            name=\"out_scale\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_scale.filter.list = [\"tif\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        max_scale = arcpy.Parameter(\n            displayName=\"Maximum Search Neighbourhood Radius (grid cells)\",\n            name=\"max_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        step = arcpy.Parameter(\n            displayName=\"Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        step.value = '1'\n\n        params = [dem, out_mag, out_scale, min_scale, max_scale, step]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        out_mag = parameters[1].valueAsText\n        out_scale = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        max_scale = parameters[4].valueAsText\n        step = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_difference_from_mean(dem=dem, out_mag=out_mag, out_scale=out_scale, min_scale=min_scale, max_scale=max_scale, step=step)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxDownslopeElevChange(object):\n    def __init__(self):\n        self.label = \"Max Downslope Elev Change\"\n        self.description = \"Calculates the maximum downslope change in elevation between a grid cell and its eight downslope neighbors.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_downslope_elev_change(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxElevDevSignature(object):\n    def __init__(self):\n        self.label = \"Max Elev Dev Signature\"\n        self.description = \"Calculates the maximum elevation deviation over a range of spatial scales and for a set of points.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        points = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"points\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        points.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        max_scale = arcpy.Parameter(\n            displayName=\"Maximum Search Neighbourhood Radius (grid cells)\",\n            name=\"max_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        step = arcpy.Parameter(\n            displayName=\"Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        step.value = '10'\n\n        params = [dem, points, output, min_scale, max_scale, step]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        points = parameters[1].valueAsText\n        if points is not None:\n            desc = arcpy.Describe(points)\n            points = desc.catalogPath\n        output = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        max_scale = parameters[4].valueAsText\n        step = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_elev_dev_signature(dem=dem, points=points, output=output, min_scale=min_scale, max_scale=max_scale, step=step)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxElevationDeviation(object):\n    def __init__(self):\n        self.label = \"Max Elevation Deviation\"\n        self.description = \"Calculates the maximum elevation deviation over a range of spatial scales.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_mag = arcpy.Parameter(\n            displayName=\"Output DEVmax Magnitude File\",\n            name=\"out_mag\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_mag.filter.list = [\"tif\"]\n\n        out_scale = arcpy.Parameter(\n            displayName=\"Output DEVmax Scale File\",\n            name=\"out_scale\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_scale.filter.list = [\"tif\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        max_scale = arcpy.Parameter(\n            displayName=\"Maximum Search Neighbourhood Radius (grid cells)\",\n            name=\"max_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        step = arcpy.Parameter(\n            displayName=\"Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        step.value = '1'\n\n        params = [dem, out_mag, out_scale, min_scale, max_scale, step]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        out_mag = parameters[1].valueAsText\n        out_scale = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        max_scale = parameters[4].valueAsText\n        step = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_elevation_deviation(dem=dem, out_mag=out_mag, out_scale=out_scale, min_scale=min_scale, max_scale=max_scale, step=step)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxOverlay(object):\n    def __init__(self):\n        self.label = \"Max Overlay\"\n        self.description = \"Evaluates the maximum value for each grid cell from a stack of input rasters.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_overlay(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxUpslopeElevChange(object):\n    def __init__(self):\n        self.label = \"Max Upslope Elev Change\"\n        self.description = \"Calculates the maximum upslope change in elevation between a grid cell and its eight downslope neighbors.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_upslope_elev_change(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxUpslopeFlowpathLength(object):\n    def __init__(self):\n        self.label = \"Max Upslope Flowpath Length\"\n        self.description = \"Measures the maximum length of all upslope flowpaths draining each grid cell.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_upslope_flowpath_length(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxUpslopeValue(object):\n    def __init__(self):\n        self.label = \"Max Upslope Value\"\n        self.description = \"Calculates the maximum upslope value from an input values raster along flowpaths.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        values = arcpy.Parameter(\n            displayName=\"Values Raster File\",\n            name=\"values\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, values, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        values = parameters[1].valueAsText\n        if values is not None:\n            desc = arcpy.Describe(values)\n            values = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_upslope_value(dem=dem, values=values, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaximalCurvature(object):\n    def __init__(self):\n        self.label = \"Maximal Curvature\"\n        self.description = \"Calculates a mean curvature raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.maximal_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaximumFilter(object):\n    def __init__(self):\n        self.label = \"Maximum Filter\"\n        self.description = \"Assigns each cell in the output grid the maximum value in a moving window centred on each grid cell in the input raster.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.maximum_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MeanCurvature(object):\n    def __init__(self):\n        self.label = \"Mean Curvature\"\n        self.description = \"Calculates a mean curvature raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.mean_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MeanFilter(object):\n    def __init__(self):\n        self.label = \"Mean Filter\"\n        self.description = \"Performs a mean filter (low-pass filter) on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '3'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '3'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.mean_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MedianFilter(object):\n    def __init__(self):\n        self.label = \"Median Filter\"\n        self.description = \"Performs a median filter on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        sig_digits = arcpy.Parameter(\n            displayName=\"Number of Significant Digits\",\n            name=\"sig_digits\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sig_digits.value = '2'\n\n        params = [i, output, filterx, filtery, sig_digits]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        sig_digits = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.median_filter(i=i, output=output, filterx=filterx, filtery=filtery, sig_digits=sig_digits)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Medoid(object):\n    def __init__(self):\n        self.label = \"Medoid\"\n        self.description = \"Calculates the medoid for a series of vector features contained in a shapefile.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.medoid(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MergeLineSegments(object):\n    def __init__(self):\n        self.label = \"Merge Line Segments\"\n        self.description = \"Merges vector line segments into larger features.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        snap = arcpy.Parameter(\n            displayName=\"Snap Tolerance\",\n            name=\"snap\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        snap.value = '0.0'\n\n        params = [i, output, snap]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        snap = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.merge_line_segments(i=i, output=output, snap=snap)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MergeTableWithCsv(object):\n    def __init__(self):\n        self.label = \"Merge Table With Csv\"\n        self.description = \"Merge a vector's attribute table with a table contained within a CSV text file.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Primary Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        pkey = arcpy.Parameter(\n            displayName=\"Primary Key Field\",\n            name=\"pkey\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        pkey.parameterDependencies = [i.name]\n\n        csv = arcpy.Parameter(\n            displayName=\"Input CSV File\",\n            name=\"csv\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        csv.filter.list = [\"csv\"]\n\n        fkey = arcpy.Parameter(\n            displayName=\"Foreign Key Field\",\n            name=\"fkey\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        fkey.parameterDependencies = [csv.name]\n\n        import_field = arcpy.Parameter(\n            displayName=\"Imported Field\",\n            name=\"import_field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        import_field.parameterDependencies = [csv.name]\n\n        params = [i, pkey, csv, fkey, import_field]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        pkey = parameters[1].valueAsText\n        csv = parameters[2].valueAsText\n        fkey = parameters[3].valueAsText\n        import_field = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.merge_table_with_csv(i=i, pkey=pkey, csv=csv, fkey=fkey, import_field=import_field)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MergeVectors(object):\n    def __init__(self):\n        self.label = \"Merge Vectors\"\n        self.description = \"Combines two or more input vectors of the same ShapeType creating a single, new output vector.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Vector Files\",\n            name=\"inputs\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.merge_vectors(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Min(object):\n    def __init__(self):\n        self.label = \"Min\"\n        self.description = \"Performs a MIN operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.min(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinAbsoluteOverlay(object):\n    def __init__(self):\n        self.label = \"Min Absolute Overlay\"\n        self.description = \"Evaluates the minimum absolute value for each grid cell from a stack of input rasters.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.min_absolute_overlay(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinDistClassification(object):\n    def __init__(self):\n        self.label = \"Min Dist Classification\"\n        self.description = \"Performs a supervised minimum-distance classification using training site polygons and multi-spectral images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Band Images\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        polys = arcpy.Parameter(\n            displayName=\"Input Training Polygons\",\n            name=\"polys\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        polys.filter.list = [\"Polygon\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Class Name Field\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [polys.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        threshold = arcpy.Parameter(\n            displayName=\"Distance Threshold (z-scores; blank for none)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [inputs, polys, field, output, threshold]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        polys = parameters[1].valueAsText\n        if polys is not None:\n            desc = arcpy.Describe(polys)\n            polys = desc.catalogPath\n        field = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        threshold = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.min_dist_classification(inputs=inputs, polys=polys, field=field, output=output, threshold=threshold)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinDownslopeElevChange(object):\n    def __init__(self):\n        self.label = \"Min Downslope Elev Change\"\n        self.description = \"Calculates the minimum downslope change in elevation between a grid cell and its eight downslope neighbors.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.min_downslope_elev_change(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinMaxContrastStretch(object):\n    def __init__(self):\n        self.label = \"Min Max Contrast Stretch\"\n        self.description = \"Performs a min-max contrast stretch on an input greytone image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        min_val = arcpy.Parameter(\n            displayName=\"Lower Tail Clip Value\",\n            name=\"min_val\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        max_val = arcpy.Parameter(\n            displayName=\"Upper Tail Clip Value\",\n            name=\"max_val\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        num_tones = arcpy.Parameter(\n            displayName=\"Number of Tones\",\n            name=\"num_tones\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_tones.value = '256'\n\n        params = [i, output, min_val, max_val, num_tones]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        min_val = parameters[2].valueAsText\n        max_val = parameters[3].valueAsText\n        num_tones = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.min_max_contrast_stretch(i=i, output=output, min_val=min_val, max_val=max_val, num_tones=num_tones)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinOverlay(object):\n    def __init__(self):\n        self.label = \"Min Overlay\"\n        self.description = \"Evaluates the minimum value for each grid cell from a stack of input rasters.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.min_overlay(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinimalCurvature(object):\n    def __init__(self):\n        self.label = \"Minimal Curvature\"\n        self.description = \"Calculates a mean curvature raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.minimal_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinimumBoundingBox(object):\n    def __init__(self):\n        self.label = \"Minimum Bounding Box\"\n        self.description = \"Creates a vector minimum bounding rectangle around vector features.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        criterion = arcpy.Parameter(\n            displayName=\"Minimization Criterion\",\n            name=\"criterion\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        criterion.filter.type = \"ValueList\"\n        criterion.filter.list = ['area', 'length', 'width', 'perimeter']\n        criterion.value = 'area'\n\n        features = arcpy.Parameter(\n            displayName=\"Find bounding rectangles around each individual feature.\",\n            name=\"features\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        features.value = 'True'\n\n        params = [i, output, criterion, features]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        criterion = parameters[2].valueAsText\n        features = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.minimum_bounding_box(i=i, output=output, criterion=criterion, features=features)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinimumBoundingCircle(object):\n    def __init__(self):\n        self.label = \"Minimum Bounding Circle\"\n        self.description = \"Delineates the minimum bounding circle (i.e. smallest enclosing circle) for a group of vectors.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        features = arcpy.Parameter(\n            displayName=\"Find bounding circle around each individual feature.\",\n            name=\"features\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        features.value = 'True'\n\n        params = [i, output, features]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        features = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.minimum_bounding_circle(i=i, output=output, features=features)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinimumBoundingEnvelope(object):\n    def __init__(self):\n        self.label = \"Minimum Bounding Envelope\"\n        self.description = \"Creates a vector axis-aligned minimum bounding rectangle (envelope) around vector features.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        features = arcpy.Parameter(\n            displayName=\"Find bounding envelop around each individual feature.\",\n            name=\"features\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        features.value = 'True'\n\n        params = [i, output, features]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        features = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.minimum_bounding_envelope(i=i, output=output, features=features)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinimumConvexHull(object):\n    def __init__(self):\n        self.label = \"Minimum Convex Hull\"\n        self.description = \"Creates a vector convex polygon around vector features.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        features = arcpy.Parameter(\n            displayName=\"Find hulls around each individual feature.\",\n            name=\"features\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        features.value = 'True'\n\n        params = [i, output, features]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        features = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.minimum_convex_hull(i=i, output=output, features=features)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinimumFilter(object):\n    def __init__(self):\n        self.label = \"Minimum Filter\"\n        self.description = \"Assigns each cell in the output grid the minimum value in a moving window centred on each grid cell in the input raster.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.minimum_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ModifiedKMeansClustering(object):\n    def __init__(self):\n        self.label = \"Modified K Means Clustering\"\n        self.description = \"Performs a modified k-means clustering operation on a multi-spectral dataset.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_html = arcpy.Parameter(\n            displayName=\"Output HTML Report File\",\n            name=\"out_html\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_html.filter.list = [\"html\"]\n\n        start_clusters = arcpy.Parameter(\n            displayName=\"Initial Num. of Clusters\",\n            name=\"start_clusters\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        start_clusters.value = '1000'\n\n        merge_dist = arcpy.Parameter(\n            displayName=\"Cluster Merger Distance\",\n            name=\"merge_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_iterations = arcpy.Parameter(\n            displayName=\"Max. Iterations\",\n            name=\"max_iterations\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_iterations.value = '10'\n\n        class_change = arcpy.Parameter(\n            displayName=\"Percent Class Change Threshold\",\n            name=\"class_change\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        class_change.value = '2.0'\n\n        params = [inputs, output, out_html, start_clusters, merge_dist, max_iterations, class_change]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        out_html = parameters[2].valueAsText\n        start_clusters = parameters[3].valueAsText\n        merge_dist = parameters[4].valueAsText\n        max_iterations = parameters[5].valueAsText\n        class_change = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.modified_k_means_clustering(inputs=inputs, output=output, out_html=out_html, start_clusters=start_clusters, merge_dist=merge_dist, max_iterations=max_iterations, class_change=class_change)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ModifyLidar(object):\n    def __init__(self):\n        self.label = \"Modify Lidar\"\n        self.description = \"Modify points within a LiDAR point cloud based on point properties.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR Points\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        statement = arcpy.Parameter(\n            displayName=\"Statement:\",\n            name=\"statement\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        params = [i, output, statement]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        statement = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.modify_lidar(i=i, output=output, statement=statement)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ModifyNoDataValue(object):\n    def __init__(self):\n        self.label = \"Modify No Data Value\"\n        self.description = \"Modifies nodata values in a raster.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        new_value = arcpy.Parameter(\n            displayName=\"New NoData Value\",\n            name=\"new_value\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        new_value.value = '-32768.0'\n\n        params = [i, new_value]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        new_value = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.modify_no_data_value(i=i, new_value=new_value)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Modulo(object):\n    def __init__(self):\n        self.label = \"Modulo\"\n        self.description = \"Performs a modulo operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.modulo(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Mosaic(object):\n    def __init__(self):\n        self.label = \"Mosaic\"\n        self.description = \"Mosaics two or more images together.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        method = arcpy.Parameter(\n            displayName=\"Resampling Method\",\n            name=\"method\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        method.filter.type = \"ValueList\"\n        method.filter.list = ['nn', 'bilinear', 'cc']\n        method.value = 'nn'\n\n        params = [inputs, output, method]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        method = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.mosaic(inputs=inputs, output=output, method=method)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MosaicWithFeathering(object):\n    def __init__(self):\n        self.label = \"Mosaic With Feathering\"\n        self.description = \"Mosaics two images together using a feathering technique in overlapping areas to reduce edge-effects.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File To Modify\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input Reference File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        method = arcpy.Parameter(\n            displayName=\"Resampling Method\",\n            name=\"method\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        method.filter.type = \"ValueList\"\n        method.filter.list = ['nn', 'bilinear', 'cc']\n        method.value = 'cc'\n\n        weight = arcpy.Parameter(\n            displayName=\"Distance Weight\",\n            name=\"weight\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        weight.value = '4.0'\n\n        params = [input1, input2, output, method, weight]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        method = parameters[3].valueAsText\n        weight = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.mosaic_with_feathering(input1=input1, input2=input2, output=output, method=method, weight=weight)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultiPartToSinglePart(object):\n    def __init__(self):\n        self.label = \"Multi Part To Single Part\"\n        self.description = \"Converts a vector file containing multi-part features into a vector containing only single-part features.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Line or Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Line or Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        exclude_holes = arcpy.Parameter(\n            displayName=\"Exclude hole parts?\",\n            name=\"exclude_holes\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        exclude_holes.value = 'True'\n\n        params = [i, output, exclude_holes]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        exclude_holes = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multi_part_to_single_part(i=i, output=output, exclude_holes=exclude_holes)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultidirectionalHillshade(object):\n    def __init__(self):\n        self.label = \"Multidirectional Hillshade\"\n        self.description = \"Calculates a multi-direction hillshade raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        altitude = arcpy.Parameter(\n            displayName=\"Altitude (degrees)\",\n            name=\"altitude\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        altitude.value = '45.0'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        full_mode = arcpy.Parameter(\n            displayName=\"Full 360-degree mode?\",\n            name=\"full_mode\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        full_mode.value = 'False'\n\n        params = [dem, output, altitude, zfactor, full_mode]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        altitude = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        full_mode = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multidirectional_hillshade(dem=dem, output=output, altitude=altitude, zfactor=zfactor, full_mode=full_mode)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Multiply(object):\n    def __init__(self):\n        self.label = \"Multiply\"\n        self.description = \"Performs a multiplication operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multiply(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultiplyOverlay(object):\n    def __init__(self):\n        self.label = \"Multiply Overlay\"\n        self.description = \"Calculates the sum for each grid cell from a group of raster images.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multiply_overlay(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultiscaleCurvatures(object):\n    def __init__(self):\n        self.label = \"Multiscale Curvatures\"\n        self.description = \"This tool calculates several multiscale curvatures and curvature-based indices from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        curv_type = arcpy.Parameter(\n            displayName=\"Curvature Type\",\n            name=\"curv_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        curv_type.filter.type = \"ValueList\"\n        curv_type.filter.list = ['AccumulationCurv', 'Curvedness', 'DifferenceCurv', 'GaussianCurv', 'GeneratingFunction', 'HorizontalExcessCurv', 'MaximalCurv', 'MeanCurv', 'MinimalCurv', 'PlanCurv', 'ProfileCurv', 'RingCurv', 'Rotor', 'ShapeIndex', 'TangentialCurv', 'TotalCurv', 'Unsphericity', 'VerticalExcessCurv']\n        curv_type.value = 'ProfileCurv'\n\n        out_mag = arcpy.Parameter(\n            displayName=\"Output Magnitude File\",\n            name=\"out_mag\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_mag.filter.list = [\"tif\"]\n\n        out_scale = arcpy.Parameter(\n            displayName=\"Output Scale File\",\n            name=\"out_scale\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_scale.filter.list = [\"tif\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_scale.value = '0'\n\n        step = arcpy.Parameter(\n            displayName=\"Base Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step.value = '1'\n\n        num_steps = arcpy.Parameter(\n            displayName=\"Number of Steps\",\n            name=\"num_steps\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_steps.value = '1'\n\n        step_nonlinearity = arcpy.Parameter(\n            displayName=\"Step Nonlinearity\",\n            name=\"step_nonlinearity\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        step_nonlinearity.value = '1.0'\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'True'\n\n        standardize = arcpy.Parameter(\n            displayName=\"Standardize Each Scale?\",\n            name=\"standardize\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        standardize.value = 'False'\n\n        params = [dem, curv_type, out_mag, out_scale, min_scale, step, num_steps, step_nonlinearity, log, standardize]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        curv_type = parameters[1].valueAsText\n        out_mag = parameters[2].valueAsText\n        out_scale = parameters[3].valueAsText\n        min_scale = parameters[4].valueAsText\n        step = parameters[5].valueAsText\n        num_steps = parameters[6].valueAsText\n        step_nonlinearity = parameters[7].valueAsText\n        log = parameters[8].valueAsText\n        standardize = parameters[9].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multiscale_curvatures(dem=dem, curv_type=curv_type, out_mag=out_mag, out_scale=out_scale, min_scale=min_scale, step=step, num_steps=num_steps, step_nonlinearity=step_nonlinearity, log=log, standardize=standardize)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultiscaleElevationPercentile(object):\n    def __init__(self):\n        self.label = \"Multiscale Elevation Percentile\"\n        self.description = \"Calculates surface roughness over a range of spatial scales.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_mag = arcpy.Parameter(\n            displayName=\"Output Roughness Magnitude File\",\n            name=\"out_mag\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_mag.filter.list = [\"tif\"]\n\n        out_scale = arcpy.Parameter(\n            displayName=\"Output Roughness Scale File\",\n            name=\"out_scale\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_scale.filter.list = [\"tif\"]\n\n        sig_digits = arcpy.Parameter(\n            displayName=\"Number of Significant Digits\",\n            name=\"sig_digits\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sig_digits.value = '3'\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_scale.value = '4'\n\n        step = arcpy.Parameter(\n            displayName=\"Base Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step.value = '1'\n\n        num_steps = arcpy.Parameter(\n            displayName=\"Number of Steps\",\n            name=\"num_steps\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_steps.value = '10'\n\n        step_nonlinearity = arcpy.Parameter(\n            displayName=\"Step Nonlinearity\",\n            name=\"step_nonlinearity\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step_nonlinearity.value = '1.0'\n\n        params = [dem, out_mag, out_scale, sig_digits, min_scale, step, num_steps, step_nonlinearity]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        out_mag = parameters[1].valueAsText\n        out_scale = parameters[2].valueAsText\n        sig_digits = parameters[3].valueAsText\n        min_scale = parameters[4].valueAsText\n        step = parameters[5].valueAsText\n        num_steps = parameters[6].valueAsText\n        step_nonlinearity = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multiscale_elevation_percentile(dem=dem, out_mag=out_mag, out_scale=out_scale, sig_digits=sig_digits, min_scale=min_scale, step=step, num_steps=num_steps, step_nonlinearity=step_nonlinearity)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultiscaleRoughness(object):\n    def __init__(self):\n        self.label = \"Multiscale Roughness\"\n        self.description = \"Calculates surface roughness over a range of spatial scales.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_mag = arcpy.Parameter(\n            displayName=\"Output Roughness Magnitude File\",\n            name=\"out_mag\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_mag.filter.list = [\"tif\"]\n\n        out_scale = arcpy.Parameter(\n            displayName=\"Output Roughness Scale File\",\n            name=\"out_scale\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_scale.filter.list = [\"tif\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_scale.value = '1'\n\n        max_scale = arcpy.Parameter(\n            displayName=\"Maximum Search Neighbourhood Radius (grid cells)\",\n            name=\"max_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        step = arcpy.Parameter(\n            displayName=\"Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step.value = '1'\n\n        params = [dem, out_mag, out_scale, min_scale, max_scale, step]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        out_mag = parameters[1].valueAsText\n        out_scale = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        max_scale = parameters[4].valueAsText\n        step = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multiscale_roughness(dem=dem, out_mag=out_mag, out_scale=out_scale, min_scale=min_scale, max_scale=max_scale, step=step)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultiscaleRoughnessSignature(object):\n    def __init__(self):\n        self.label = \"Multiscale Roughness Signature\"\n        self.description = \"Calculates the surface roughness for points over a range of spatial scales.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        points = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"points\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        points.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_scale.value = '1'\n\n        max_scale = arcpy.Parameter(\n            displayName=\"Maximum Search Neighbourhood Radius (grid cells)\",\n            name=\"max_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        step = arcpy.Parameter(\n            displayName=\"Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step.value = '1'\n\n        params = [dem, points, output, min_scale, max_scale, step]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        points = parameters[1].valueAsText\n        if points is not None:\n            desc = arcpy.Describe(points)\n            points = desc.catalogPath\n        output = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        max_scale = parameters[4].valueAsText\n        step = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multiscale_roughness_signature(dem=dem, points=points, output=output, min_scale=min_scale, max_scale=max_scale, step=step)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultiscaleStdDevNormals(object):\n    def __init__(self):\n        self.label = \"Multiscale Std Dev Normals\"\n        self.description = \"Calculates surface roughness over a range of spatial scales.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_mag = arcpy.Parameter(\n            displayName=\"Output Roughness Magnitude File\",\n            name=\"out_mag\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_mag.filter.list = [\"tif\"]\n\n        out_scale = arcpy.Parameter(\n            displayName=\"Output Roughness Scale File\",\n            name=\"out_scale\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_scale.filter.list = [\"tif\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_scale.value = '1'\n\n        step = arcpy.Parameter(\n            displayName=\"Base Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step.value = '1'\n\n        num_steps = arcpy.Parameter(\n            displayName=\"Number of Steps\",\n            name=\"num_steps\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_steps.value = '10'\n\n        step_nonlinearity = arcpy.Parameter(\n            displayName=\"Step Nonlinearity\",\n            name=\"step_nonlinearity\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        step_nonlinearity.value = '1.0'\n\n        params = [dem, out_mag, out_scale, min_scale, step, num_steps, step_nonlinearity]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        out_mag = parameters[1].valueAsText\n        out_scale = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        step = parameters[4].valueAsText\n        num_steps = parameters[5].valueAsText\n        step_nonlinearity = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multiscale_std_dev_normals(dem=dem, out_mag=out_mag, out_scale=out_scale, min_scale=min_scale, step=step, num_steps=num_steps, step_nonlinearity=step_nonlinearity)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultiscaleStdDevNormalsSignature(object):\n    def __init__(self):\n        self.label = \"Multiscale Std Dev Normals Signature\"\n        self.description = \"Calculates the surface roughness for points over a range of spatial scales.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        points = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"points\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        points.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_scale.value = '1'\n\n        step = arcpy.Parameter(\n            displayName=\"Base Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step.value = '1'\n\n        num_steps = arcpy.Parameter(\n            displayName=\"Number of Steps\",\n            name=\"num_steps\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_steps.value = '10'\n\n        step_nonlinearity = arcpy.Parameter(\n            displayName=\"Step Nonlinearity\",\n            name=\"step_nonlinearity\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        step_nonlinearity.value = '1.0'\n\n        params = [dem, points, output, min_scale, step, num_steps, step_nonlinearity]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        points = parameters[1].valueAsText\n        if points is not None:\n            desc = arcpy.Describe(points)\n            points = desc.catalogPath\n        output = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        step = parameters[4].valueAsText\n        num_steps = parameters[5].valueAsText\n        step_nonlinearity = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multiscale_std_dev_normals_signature(dem=dem, points=points, output=output, min_scale=min_scale, step=step, num_steps=num_steps, step_nonlinearity=step_nonlinearity)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultiscaleTopographicPositionImage(object):\n    def __init__(self):\n        self.label = \"Multiscale Topographic Position Image\"\n        self.description = \"Creates a multiscale topographic position image from three DEVmax rasters of differing spatial scale ranges.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        local = arcpy.Parameter(\n            displayName=\"Input Local-Scale File\",\n            name=\"local\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        meso = arcpy.Parameter(\n            displayName=\"Input Meso-Scale File\",\n            name=\"meso\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        broad = arcpy.Parameter(\n            displayName=\"Input Broad-Scale File\",\n            name=\"broad\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        hillshade = arcpy.Parameter(\n            displayName=\"Optional Hillshade File\",\n            name=\"hillshade\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        lightness = arcpy.Parameter(\n            displayName=\"Image Lightness Value\",\n            name=\"lightness\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        lightness.value = '1.2'\n\n        params = [local, meso, broad, hillshade, output, lightness]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        local = parameters[0].valueAsText\n        if local is not None:\n            desc = arcpy.Describe(local)\n            local = desc.catalogPath\n        meso = parameters[1].valueAsText\n        if meso is not None:\n            desc = arcpy.Describe(meso)\n            meso = desc.catalogPath\n        broad = parameters[2].valueAsText\n        if broad is not None:\n            desc = arcpy.Describe(broad)\n            broad = desc.catalogPath\n        hillshade = parameters[3].valueAsText\n        if hillshade is not None:\n            desc = arcpy.Describe(hillshade)\n            hillshade = desc.catalogPath\n        output = parameters[4].valueAsText\n        lightness = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multiscale_topographic_position_image(local=local, meso=meso, broad=broad, hillshade=hillshade, output=output, lightness=lightness)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NarrownessIndex(object):\n    def __init__(self):\n        self.label = \"Narrowness Index\"\n        self.description = \"Calculates the narrowness of raster polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.narrowness_index(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NaturalNeighbourInterpolation(object):\n    def __init__(self):\n        self.label = \"Natural Neighbour Interpolation\"\n        self.description = \"Creates a raster grid based on Sibson's natural neighbour method.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        use_z = arcpy.Parameter(\n            displayName=\"Use Shapefile 'z' values?\",\n            name=\"use_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_z.value = 'False'\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip to convex hull?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = 'True'\n\n        params = [i, field, use_z, output, cell_size, base, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        use_z = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        cell_size = parameters[4].valueAsText\n        base = parameters[5].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        clip = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.natural_neighbour_interpolation(i=i, field=field, use_z=use_z, output=output, cell_size=cell_size, base=base, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NearestNeighbourGridding(object):\n    def __init__(self):\n        self.label = \"Nearest Neighbour Gridding\"\n        self.description = \"Creates a raster grid based on a set of vector points and assigns grid values using the nearest neighbour.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        use_z = arcpy.Parameter(\n            displayName=\"Use z-coordinate instead of field?\",\n            name=\"use_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_z.value = 'False'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_dist = arcpy.Parameter(\n            displayName=\"Maximum Search Distance\",\n            name=\"max_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, use_z, output, cell_size, base, max_dist]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        use_z = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        cell_size = parameters[4].valueAsText\n        base = parameters[5].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        max_dist = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.nearest_neighbour_gridding(i=i, field=field, use_z=use_z, output=output, cell_size=cell_size, base=base, max_dist=max_dist)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Negate(object):\n    def __init__(self):\n        self.label = \"Negate\"\n        self.description = \"Changes the sign of values in a raster or the 0-1 values of a Boolean raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.negate(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NewRasterFromBase(object):\n    def __init__(self):\n        self.label = \"New Raster From Base\"\n        self.description = \"Creates a new raster using a base image.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        base = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"base\",\n            datatype=[\"DERasterDataset\", \"DEShapefile\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        value = arcpy.Parameter(\n            displayName=\"Constant Value\",\n            name=\"value\",\n            datatype=[\"GPString\", \"GPDouble\"],\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        value.value = 'nodata'\n\n        data_type = arcpy.Parameter(\n            displayName=\"Data Type\",\n            name=\"data_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        data_type.filter.type = \"ValueList\"\n        data_type.filter.list = ['double', 'float', 'integer']\n        data_type.value = 'float'\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [base, output, value, data_type, cell_size]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        base = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        value = parameters[2].valueAsText\n        data_type = parameters[3].valueAsText\n        cell_size = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.new_raster_from_base(base=base, output=output, value=value, data_type=data_type, cell_size=cell_size)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NormalVectors(object):\n    def __init__(self):\n        self.label = \"Normal Vectors\"\n        self.description = \"Calculates normal vectors for points within a LAS file and stores these data (XYZ vector components) in the RGB field.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        radius.value = '1.0'\n\n        params = [i, output, radius]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        radius = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.normal_vectors(i=i, output=output, radius=radius)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NormalizeLidar(object):\n    def __init__(self):\n        self.label = \"Normalize Lidar\"\n        self.description = \"Normalizes a LiDAR point cloud.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Lidar File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        dtm = arcpy.Parameter(\n            displayName=\"Input DTM Raster File\",\n            name=\"dtm\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, output, dtm]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        dtm = parameters[2].valueAsText\n        if dtm is not None:\n            desc = arcpy.Describe(dtm)\n            dtm = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.normalize_lidar(i=i, output=output, dtm=dtm)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NormalizedDifferenceIndex(object):\n    def __init__(self):\n        self.label = \"Normalized Difference Index\"\n        self.description = \"Calculate a normalized-difference index (NDI) from two bands of multispectral image data.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input 1 File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input 2 File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        clip = arcpy.Parameter(\n            displayName=\"Distribution Tail Clip Amount (%)\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '0.0'\n\n        correction = arcpy.Parameter(\n            displayName=\"Correction value\",\n            name=\"correction\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        correction.value = '0.0'\n\n        params = [input1, input2, output, clip, correction]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        clip = parameters[3].valueAsText\n        correction = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.normalized_difference_index(input1=input1, input2=input2, output=output, clip=clip, correction=correction)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Not(object):\n    def __init__(self):\n        self.label = \"Not\"\n        self.description = \"Performs a logical NOT operator on two Boolean raster images.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.Not(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NotEqualTo(object):\n    def __init__(self):\n        self.label = \"Not Equal To\"\n        self.description = \"Performs a not-equal-to comparison operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.not_equal_to(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NumDownslopeNeighbours(object):\n    def __init__(self):\n        self.label = \"Num Downslope Neighbours\"\n        self.description = \"Calculates the number of downslope neighbours to each grid cell in a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.num_downslope_neighbours(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NumInflowingNeighbours(object):\n    def __init__(self):\n        self.label = \"Num Inflowing Neighbours\"\n        self.description = \"Computes the number of inflowing neighbours to each cell in an input DEM based on the D8 algorithm.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.num_inflowing_neighbours(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NumUpslopeNeighbours(object):\n    def __init__(self):\n        self.label = \"Num Upslope Neighbours\"\n        self.description = \"Calculates the number of upslope neighbours to each grid cell in a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.num_upslope_neighbours(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass OlympicFilter(object):\n    def __init__(self):\n        self.label = \"Olympic Filter\"\n        self.description = \"Performs an olympic smoothing filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.olympic_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Opening(object):\n    def __init__(self):\n        self.label = \"Opening\"\n        self.description = \"An opening is a mathematical morphology operation involving a dilation (max filter) of an erosion (min filter) set.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.opening(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Openness(object):\n    def __init__(self):\n        self.label = \"Openness\"\n        self.description = \"This tool calculates the topographic openness index from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        pos_output = arcpy.Parameter(\n            displayName=\"Positive Openness Output Raster\",\n            name=\"pos_output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        pos_output.filter.list = [\"tif\"]\n\n        neg_output = arcpy.Parameter(\n            displayName=\"Negative Openness Output Raster\",\n            name=\"neg_output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        neg_output.filter.list = [\"tif\"]\n\n        dist = arcpy.Parameter(\n            displayName=\"Search Distance (grid cells)\",\n            name=\"dist\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        dist.value = '20'\n\n        params = [i, pos_output, neg_output, dist]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        pos_output = parameters[1].valueAsText\n        neg_output = parameters[2].valueAsText\n        dist = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.openness(i=i, pos_output=pos_output, neg_output=neg_output, dist=dist)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Or(object):\n    def __init__(self):\n        self.label = \"Or\"\n        self.description = \"Performs a logical OR operator on two Boolean raster images.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.Or(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PairedSampleTTest(object):\n    def __init__(self):\n        self.label = \"Paired Sample T Test\"\n        self.description = \"Performs a 2-sample K-S test for significant differences on two input rasters.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"First Input File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Second Input File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        num_samples = arcpy.Parameter(\n            displayName=\"Num. Samples (blank for whole image)\",\n            name=\"num_samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [input1, input2, output, num_samples]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        num_samples = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.paired_sample_t_test(input1=input1, input2=input2, output=output, num_samples=num_samples)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PanchromaticSharpening(object):\n    def __init__(self):\n        self.label = \"Panchromatic Sharpening\"\n        self.description = \"Increases the spatial resolution of image data by combining multispectral bands with panchromatic data.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        red = arcpy.Parameter(\n            displayName=\"Input Red Band File (optional; only if colour-composite not specified)\",\n            name=\"red\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        green = arcpy.Parameter(\n            displayName=\"Input Green Band File (optional; only if colour-composite not specified)\",\n            name=\"green\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        blue = arcpy.Parameter(\n            displayName=\"Input Blue Band File (optional; only if colour-composite not specified)\",\n            name=\"blue\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        composite = arcpy.Parameter(\n            displayName=\"Input Colour-Composite Image File (optional; only if individual bands not specified)\",\n            name=\"composite\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        pan = arcpy.Parameter(\n            displayName=\"Input Panchromatic Band File\",\n            name=\"pan\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Colour Composite File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        method = arcpy.Parameter(\n            displayName=\"Pan-Sharpening Method\",\n            name=\"method\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        method.filter.type = \"ValueList\"\n        method.filter.list = ['brovey', 'ihs']\n        method.value = 'brovey'\n\n        params = [red, green, blue, composite, pan, output, method]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        red = parameters[0].valueAsText\n        if red is not None:\n            desc = arcpy.Describe(red)\n            red = desc.catalogPath\n        green = parameters[1].valueAsText\n        if green is not None:\n            desc = arcpy.Describe(green)\n            green = desc.catalogPath\n        blue = parameters[2].valueAsText\n        if blue is not None:\n            desc = arcpy.Describe(blue)\n            blue = desc.catalogPath\n        composite = parameters[3].valueAsText\n        if composite is not None:\n            desc = arcpy.Describe(composite)\n            composite = desc.catalogPath\n        pan = parameters[4].valueAsText\n        if pan is not None:\n            desc = arcpy.Describe(pan)\n            pan = desc.catalogPath\n        output = parameters[5].valueAsText\n        method = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.panchromatic_sharpening(red=red, green=green, blue=blue, composite=composite, pan=pan, output=output, method=method)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ParallelepipedClassification(object):\n    def __init__(self):\n        self.label = \"Parallelepiped Classification\"\n        self.description = \"Performs a supervised parallelepiped classification using training site polygons and multi-spectral images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Band Images\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        polys = arcpy.Parameter(\n            displayName=\"Input Training Polygons\",\n            name=\"polys\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        polys.filter.list = [\"Polygon\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Class Name Field\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [polys.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, polys, field, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        polys = parameters[1].valueAsText\n        if polys is not None:\n            desc = arcpy.Describe(polys)\n            polys = desc.catalogPath\n        field = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.parallelepiped_classification(inputs=inputs, polys=polys, field=field, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PatchOrientation(object):\n    def __init__(self):\n        self.label = \"Patch Orientation\"\n        self.description = \"Calculates the orientation of vector polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.patch_orientation(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PennockLandformClass(object):\n    def __init__(self):\n        self.label = \"Pennock Landform Class\"\n        self.description = \"Classifies hillslope zones based on slope, profile curvature, and plan curvature.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        slope = arcpy.Parameter(\n            displayName=\"Slope Threshold (degrees)\",\n            name=\"slope\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        slope.value = '3.0'\n\n        prof = arcpy.Parameter(\n            displayName=\"Profile Curvature Threshold\",\n            name=\"prof\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        prof.value = '0.1'\n\n        plan = arcpy.Parameter(\n            displayName=\"Plan Curvature Threshold\",\n            name=\"plan\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        plan.value = '0.0'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, slope, prof, plan, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        slope = parameters[2].valueAsText\n        prof = parameters[3].valueAsText\n        plan = parameters[4].valueAsText\n        zfactor = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.pennock_landform_class(dem=dem, output=output, slope=slope, prof=prof, plan=plan, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PercentElevRange(object):\n    def __init__(self):\n        self.label = \"Percent Elev Range\"\n        self.description = \"Calculates percent of elevation range from a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '3'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '3'\n\n        params = [dem, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.percent_elev_range(dem=dem, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PercentEqualTo(object):\n    def __init__(self):\n        self.label = \"Percent Equal To\"\n        self.description = \"Calculates the percentage of a raster stack that have cell values equal to an input on a cell-by-cell basis.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        comparison = arcpy.Parameter(\n            displayName=\"Input Comparison File\",\n            name=\"comparison\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, comparison, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        comparison = parameters[1].valueAsText\n        if comparison is not None:\n            desc = arcpy.Describe(comparison)\n            comparison = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.percent_equal_to(inputs=inputs, comparison=comparison, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PercentGreaterThan(object):\n    def __init__(self):\n        self.label = \"Percent Greater Than\"\n        self.description = \"Calculates the percentage of a raster stack that have cell values greater than an input on a cell-by-cell basis.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        comparison = arcpy.Parameter(\n            displayName=\"Input Comparison File\",\n            name=\"comparison\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, comparison, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        comparison = parameters[1].valueAsText\n        if comparison is not None:\n            desc = arcpy.Describe(comparison)\n            comparison = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.percent_greater_than(inputs=inputs, comparison=comparison, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PercentLessThan(object):\n    def __init__(self):\n        self.label = \"Percent Less Than\"\n        self.description = \"Calculates the percentage of a raster stack that have cell values less than an input on a cell-by-cell basis.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        comparison = arcpy.Parameter(\n            displayName=\"Input Comparison File\",\n            name=\"comparison\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, comparison, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        comparison = parameters[1].valueAsText\n        if comparison is not None:\n            desc = arcpy.Describe(comparison)\n            comparison = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.percent_less_than(inputs=inputs, comparison=comparison, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PercentageContrastStretch(object):\n    def __init__(self):\n        self.label = \"Percentage Contrast Stretch\"\n        self.description = \"Performs a percentage linear contrast stretch on input images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        clip = arcpy.Parameter(\n            displayName=\"Distribution Tail Clip Amount (%)\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '1.0'\n\n        tail = arcpy.Parameter(\n            displayName=\"Tail\",\n            name=\"tail\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        tail.filter.type = \"ValueList\"\n        tail.filter.list = ['upper', 'lower', 'both']\n        tail.value = 'both'\n\n        num_tones = arcpy.Parameter(\n            displayName=\"Number of Tones\",\n            name=\"num_tones\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_tones.value = '256'\n\n        params = [i, output, clip, tail, num_tones]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        clip = parameters[2].valueAsText\n        tail = parameters[3].valueAsText\n        num_tones = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.percentage_contrast_stretch(i=i, output=output, clip=clip, tail=tail, num_tones=num_tones)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PercentileFilter(object):\n    def __init__(self):\n        self.label = \"Percentile Filter\"\n        self.description = \"Performs a percentile filter on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        sig_digits = arcpy.Parameter(\n            displayName=\"Number of Significant Digits\",\n            name=\"sig_digits\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sig_digits.value = '2'\n\n        params = [i, output, filterx, filtery, sig_digits]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        sig_digits = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.percentile_filter(i=i, output=output, filterx=filterx, filtery=filtery, sig_digits=sig_digits)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PerimeterAreaRatio(object):\n    def __init__(self):\n        self.label = \"Perimeter Area Ratio\"\n        self.description = \"Calculates the perimeter-area ratio of vector polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.perimeter_area_ratio(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PhiCoefficient(object):\n    def __init__(self):\n        self.label = \"Phi Coefficient\"\n        self.description = \"This tool performs a binary classification accuracy assessment.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input Raster Image 1\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input Raster Image 2\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.phi_coefficient(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PickFromList(object):\n    def __init__(self):\n        self.label = \"Pick From List\"\n        self.description = \"Outputs the value from a raster stack specified by a position raster.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        pos_input = arcpy.Parameter(\n            displayName=\"Input Position File\",\n            name=\"pos_input\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, pos_input, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        pos_input = parameters[1].valueAsText\n        if pos_input is not None:\n            desc = arcpy.Describe(pos_input)\n            pos_input = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.pick_from_list(inputs=inputs, pos_input=pos_input, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PiecewiseContrastStretch(object):\n    def __init__(self):\n        self.label = \"Piecewise Contrast Stretch\"\n        self.description = \"Performs a piecewise contrast stretch on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster Image\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        function = arcpy.Parameter(\n            displayName=\"Piecewise Function Break-points:\",\n            name=\"function\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        greytones = arcpy.Parameter(\n            displayName=\"Number of Output Greytones:\",\n            name=\"greytones\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        greytones.value = '1024'\n\n        params = [i, output, function, greytones]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        function = parameters[2].valueAsText\n        greytones = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.piecewise_contrast_stretch(i=i, output=output, function=function, greytones=greytones)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PlanCurvature(object):\n    def __init__(self):\n        self.label = \"Plan Curvature\"\n        self.description = \"Calculates a plan (contour) curvature raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.plan_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PolygonArea(object):\n    def __init__(self):\n        self.label = \"Polygon Area\"\n        self.description = \"Calculates the area of vector polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.polygon_area(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PolygonLongAxis(object):\n    def __init__(self):\n        self.label = \"Polygon Long Axis\"\n        self.description = \"Used to map the long axis of polygon features.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.polygon_long_axis(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PolygonPerimeter(object):\n    def __init__(self):\n        self.label = \"Polygon Perimeter\"\n        self.description = \"Calculates the perimeter of vector polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.polygon_perimeter(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PolygonShortAxis(object):\n    def __init__(self):\n        self.label = \"Polygon Short Axis\"\n        self.description = \"Used to map the short axis of polygon features.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.polygon_short_axis(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Polygonize(object):\n    def __init__(self):\n        self.label = \"Polygonize\"\n        self.description = \"Creates a polygon layer from two or more intersecting line features contained in one or more input vector line files.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Vector Lines File\",\n            name=\"inputs\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n        inputs.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.polygonize(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PolygonsToLines(object):\n    def __init__(self):\n        self.label = \"Polygons To Lines\"\n        self.description = \"Converts vector polygons to polylines.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Line File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.polygons_to_lines(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Power(object):\n    def __init__(self):\n        self.label = \"Power\"\n        self.description = \"Raises the values in grid cells of one rasters, or a constant value, by values in another raster or constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.power(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PrewittFilter(object):\n    def __init__(self):\n        self.label = \"Prewitt Filter\"\n        self.description = \"Performs a Prewitt edge-detection filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        clip = arcpy.Parameter(\n            displayName=\"Distribution Tail Clip Amount (Percent)\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '0.0'\n\n        params = [i, output, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        clip = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.prewitt_filter(i=i, output=output, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PrincipalComponentAnalysis(object):\n    def __init__(self):\n        self.label = \"Principal Component Analysis\"\n        self.description = \"Performs a principal component analysis (PCA) on a multi-spectral dataset.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML Report File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        num_comp = arcpy.Parameter(\n            displayName=\"Num. of Component Images (blank for all)\",\n            name=\"num_comp\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        standardized = arcpy.Parameter(\n            displayName=\"Perform Standaradized PCA?\",\n            name=\"standardized\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [inputs, output, num_comp, standardized]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        num_comp = parameters[2].valueAsText\n        standardized = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.principal_component_analysis(inputs=inputs, output=output, num_comp=num_comp, standardized=standardized)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PrintGeoTiffTags(object):\n    def __init__(self):\n        self.label = \"Print Geo Tiff Tags\"\n        self.description = \"Prints the tags within a GeoTIFF.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input GeoTIFF Raster File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.print_geo_tiff_tags(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Profile(object):\n    def __init__(self):\n        self.label = \"Profile\"\n        self.description = \"Plots profiles from digital surface models.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        lines = arcpy.Parameter(\n            displayName=\"Input Vector Line File\",\n            name=\"lines\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        lines.filter.list = [\"Polyline\"]\n\n        surface = arcpy.Parameter(\n            displayName=\"Input Surface File\",\n            name=\"surface\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [lines, surface, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        lines = parameters[0].valueAsText\n        if lines is not None:\n            desc = arcpy.Describe(lines)\n            lines = desc.catalogPath\n        surface = parameters[1].valueAsText\n        if surface is not None:\n            desc = arcpy.Describe(surface)\n            surface = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.profile(lines=lines, surface=surface, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ProfileCurvature(object):\n    def __init__(self):\n        self.label = \"Profile Curvature\"\n        self.description = \"Calculates a profile curvature raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.profile_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass QinFlowAccumulation(object):\n    def __init__(self):\n        self.label = \"Qin Flow Accumulation\"\n        self.description = \"Calculates Qin et al. (2007) flow accumulation.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['cells', 'specific contributing area', 'catchment area']\n        out_type.value = 'specific contributing area'\n\n        exponent = arcpy.Parameter(\n            displayName=\"Upper-bound Exponent Parameter\",\n            name=\"exponent\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        exponent.value = '10.0'\n\n        max_slope = arcpy.Parameter(\n            displayName=\"Upper-bound Slope Parameter (in degrees)\",\n            name=\"max_slope\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_slope.value = '45.0'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Convergence Threshold (grid cells; blank for none)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip the upper tail by 1%?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = 'False'\n\n        params = [dem, output, out_type, exponent, max_slope, threshold, log, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_type = parameters[2].valueAsText\n        exponent = parameters[3].valueAsText\n        max_slope = parameters[4].valueAsText\n        threshold = parameters[5].valueAsText\n        log = parameters[6].valueAsText\n        clip = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.qin_flow_accumulation(dem=dem, output=output, out_type=out_type, exponent=exponent, max_slope=max_slope, threshold=threshold, log=log, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Quantiles(object):\n    def __init__(self):\n        self.label = \"Quantiles\"\n        self.description = \"Transforms raster values into quantiles.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        num_quantiles = arcpy.Parameter(\n            displayName=\"Number of Quantiles\",\n            name=\"num_quantiles\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_quantiles.value = '5'\n\n        params = [i, output, num_quantiles]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        num_quantiles = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.quantiles(i=i, output=output, num_quantiles=num_quantiles)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass QuinnFlowAccumulation(object):\n    def __init__(self):\n        self.label = \"Quinn Flow Accumulation\"\n        self.description = \"Calculates Quinn et al. (1995) flow accumulation.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['cells', 'specific contributing area', 'catchment area']\n        out_type.value = 'specific contributing area'\n\n        exponent = arcpy.Parameter(\n            displayName=\"Exponent Parameter\",\n            name=\"exponent\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        exponent.value = '1.0'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Convergence Threshold (grid cells; blank for none)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip the upper tail by 1%?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = 'False'\n\n        params = [dem, output, out_type, exponent, threshold, log, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_type = parameters[2].valueAsText\n        exponent = parameters[3].valueAsText\n        threshold = parameters[4].valueAsText\n        log = parameters[5].valueAsText\n        clip = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.quinn_flow_accumulation(dem=dem, output=output, out_type=out_type, exponent=exponent, threshold=threshold, log=log, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RadialBasisFunctionInterpolation(object):\n    def __init__(self):\n        self.label = \"Radial Basis Function Interpolation\"\n        self.description = \"Interpolates vector points into a raster surface using a radial basis function scheme.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        use_z = arcpy.Parameter(\n            displayName=\"Use z-coordinate instead of field?\",\n            name=\"use_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_z.value = 'False'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius (map units)\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        min_points = arcpy.Parameter(\n            displayName=\"Min. Number of Points\",\n            name=\"min_points\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        func_type = arcpy.Parameter(\n            displayName=\"Radial Basis Function Type\",\n            name=\"func_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        func_type.filter.type = \"ValueList\"\n        func_type.filter.list = ['ThinPlateSpline', 'PolyHarmonic', 'Gaussian', 'MultiQuadric', 'InverseMultiQuadric']\n        func_type.value = 'ThinPlateSpline'\n\n        poly_order = arcpy.Parameter(\n            displayName=\"Polynomial Order\",\n            name=\"poly_order\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        poly_order.filter.type = \"ValueList\"\n        poly_order.filter.list = ['none', 'constant', 'affine']\n        poly_order.value = 'none'\n\n        weight = arcpy.Parameter(\n            displayName=\"Weight\",\n            name=\"weight\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        weight.value = '0.1'\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, use_z, output, radius, min_points, func_type, poly_order, weight, cell_size, base]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        use_z = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        radius = parameters[4].valueAsText\n        min_points = parameters[5].valueAsText\n        func_type = parameters[6].valueAsText\n        poly_order = parameters[7].valueAsText\n        weight = parameters[8].valueAsText\n        cell_size = parameters[9].valueAsText\n        base = parameters[10].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.radial_basis_function_interpolation(i=i, field=field, use_z=use_z, output=output, radius=radius, min_points=min_points, func_type=func_type, poly_order=poly_order, weight=weight, cell_size=cell_size, base=base)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RadiusOfGyration(object):\n    def __init__(self):\n        self.label = \"Radius Of Gyration\"\n        self.description = \"Calculates the distance of cells from their polygon's centroid.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        text_output = arcpy.Parameter(\n            displayName=\"Output text?\",\n            name=\"text_output\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, output, text_output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        text_output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.radius_of_gyration(i=i, output=output, text_output=text_output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RaiseWalls(object):\n    def __init__(self):\n        self.label = \"Raise Walls\"\n        self.description = \"Raises walls in a DEM along a line or around a polygon, e.g. a watershed.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        input = arcpy.Parameter(\n            displayName=\"Input Vector Line or Polygon File\",\n            name=\"input\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        breach = arcpy.Parameter(\n            displayName=\"Input Breach Lines (optional)\",\n            name=\"breach\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        breach.filter.list = [\"Polyline\"]\n\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        height = arcpy.Parameter(\n            displayName=\"Wall Height\",\n            name=\"height\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        height.value = '100.0'\n\n        params = [input, breach, dem, output, height]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        breach = parameters[1].valueAsText\n        if breach is not None:\n            desc = arcpy.Describe(breach)\n            breach = desc.catalogPath\n        dem = parameters[2].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[3].valueAsText\n        height = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raise_walls(i=i, breach=breach, dem=dem, output=output, height=height)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RandomField(object):\n    def __init__(self):\n        self.label = \"Random Field\"\n        self.description = \"Creates an image containing random values.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        base = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [base, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        base = parameters[0].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.random_field(base=base, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RandomForestClassification(object):\n    def __init__(self):\n        self.label = \"Random Forest Classification\"\n        self.description = \"Performs a supervised random forest classification using training site polygons/points and predictor rasters.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Predictor Rasters\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        training = arcpy.Parameter(\n            displayName=\"Input Training Polygons/Points\",\n            name=\"training\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        field = arcpy.Parameter(\n            displayName=\"Class Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [training.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        split_criterion = arcpy.Parameter(\n            displayName=\"Split Criterion\",\n            name=\"split_criterion\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        split_criterion.filter.type = \"ValueList\"\n        split_criterion.filter.list = ['Gini', 'Entropy', 'ClassificationError']\n        split_criterion.value = 'Gini'\n\n        n_trees = arcpy.Parameter(\n            displayName=\"Number of Trees in Forest\",\n            name=\"n_trees\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        n_trees.value = '500'\n\n        min_samples_leaf = arcpy.Parameter(\n            displayName=\"Min Number of Samples to be a Leaf\",\n            name=\"min_samples_leaf\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_samples_leaf.value = '1'\n\n        min_samples_split = arcpy.Parameter(\n            displayName=\"Min Number of Samples Needed to Split Node\",\n            name=\"min_samples_split\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_samples_split.value = '2'\n\n        test_proportion = arcpy.Parameter(\n            displayName=\"Test Proportion\",\n            name=\"test_proportion\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        test_proportion.value = '0.2'\n\n        params = [inputs, training, field, output, split_criterion, n_trees, min_samples_leaf, min_samples_split, test_proportion]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        training = parameters[1].valueAsText\n        if training is not None:\n            desc = arcpy.Describe(training)\n            training = desc.catalogPath\n        field = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        split_criterion = parameters[4].valueAsText\n        n_trees = parameters[5].valueAsText\n        min_samples_leaf = parameters[6].valueAsText\n        min_samples_split = parameters[7].valueAsText\n        test_proportion = parameters[8].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.random_forest_classification(inputs=inputs, training=training, field=field, output=output, split_criterion=split_criterion, n_trees=n_trees, min_samples_leaf=min_samples_leaf, min_samples_split=min_samples_split, test_proportion=test_proportion)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RandomForestRegression(object):\n    def __init__(self):\n        self.label = \"Random Forest Regression\"\n        self.description = \"Performs a random forest regression analysis using training site data and predictor rasters.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Predictor Rasters\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        training = arcpy.Parameter(\n            displayName=\"Input Training Points\",\n            name=\"training\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        training.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Response Variable Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [training.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        n_trees = arcpy.Parameter(\n            displayName=\"Number of Trees in Forest\",\n            name=\"n_trees\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        n_trees.value = '100'\n\n        min_samples_leaf = arcpy.Parameter(\n            displayName=\"Min Number of Samples to be a Leaf\",\n            name=\"min_samples_leaf\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_samples_leaf.value = '1'\n\n        min_samples_split = arcpy.Parameter(\n            displayName=\"Min Number of Samples Needed to Split Node\",\n            name=\"min_samples_split\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_samples_split.value = '2'\n\n        test_proportion = arcpy.Parameter(\n            displayName=\"Test Proportion\",\n            name=\"test_proportion\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        test_proportion.value = '0.2'\n\n        params = [inputs, training, field, output, n_trees, min_samples_leaf, min_samples_split, test_proportion]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        training = parameters[1].valueAsText\n        if training is not None:\n            desc = arcpy.Describe(training)\n            training = desc.catalogPath\n        field = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        n_trees = parameters[4].valueAsText\n        min_samples_leaf = parameters[5].valueAsText\n        min_samples_split = parameters[6].valueAsText\n        test_proportion = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.random_forest_regression(inputs=inputs, training=training, field=field, output=output, n_trees=n_trees, min_samples_leaf=min_samples_leaf, min_samples_split=min_samples_split, test_proportion=test_proportion)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RandomSample(object):\n    def __init__(self):\n        self.label = \"Random Sample\"\n        self.description = \"Creates an image containing randomly located sample grid cells with unique IDs.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        base = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        num_samples = arcpy.Parameter(\n            displayName=\"Num. Samples\",\n            name=\"num_samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_samples.value = '1000'\n\n        params = [base, output, num_samples]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        base = parameters[0].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        output = parameters[1].valueAsText\n        num_samples = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.random_sample(base=base, output=output, num_samples=num_samples)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RangeFilter(object):\n    def __init__(self):\n        self.label = \"Range Filter\"\n        self.description = \"Assigns each cell in the output grid the range of values in a moving window centred on each grid cell in the input raster.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.range_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterArea(object):\n    def __init__(self):\n        self.label = \"Raster Area\"\n        self.description = \"Calculates the area of polygons or classes within a raster image.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_text = arcpy.Parameter(\n            displayName=\"Output text?\",\n            name=\"out_text\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        units = arcpy.Parameter(\n            displayName=\"Units\",\n            name=\"units\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        units.filter.type = \"ValueList\"\n        units.filter.list = ['grid cells', 'map units']\n        units.value = 'grid cells'\n\n        zero_back = arcpy.Parameter(\n            displayName=\"Treat zero values as background?\",\n            name=\"zero_back\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, output, out_text, units, zero_back]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_text = parameters[2].valueAsText\n        units = parameters[3].valueAsText\n        zero_back = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_area(i=i, output=output, out_text=out_text, units=units, zero_back=zero_back)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterCalculator(object):\n    def __init__(self):\n        self.label = \"Raster Calculator\"\n        self.description = \"Performs a complex mathematical operations on one or more input raster images on a cell-to-cell basis.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        statement = arcpy.Parameter(\n            displayName=\"Statement:\",\n            name=\"statement\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [statement, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        statement = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_calculator(statement=statement, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterCellAssignment(object):\n    def __init__(self):\n        self.label = \"Raster Cell Assignment\"\n        self.description = \"Assign row or column number to cells.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        assign = arcpy.Parameter(\n            displayName=\"Which spatial variable should be assigned?\",\n            name=\"assign\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        assign.filter.type = \"ValueList\"\n        assign.filter.list = ['column', 'row', 'x', 'y']\n        assign.value = 'column'\n\n        params = [i, output, assign]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        assign = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_cell_assignment(i=i, output=output, assign=assign)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterHistogram(object):\n    def __init__(self):\n        self.label = \"Raster Histogram\"\n        self.description = \"Creates a histogram from raster values.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_histogram(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterPerimeter(object):\n    def __init__(self):\n        self.label = \"Raster Perimeter\"\n        self.description = \"Calculates the perimeters of polygons or classes within a raster image.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_text = arcpy.Parameter(\n            displayName=\"Output text?\",\n            name=\"out_text\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        units = arcpy.Parameter(\n            displayName=\"Units\",\n            name=\"units\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        units.filter.type = \"ValueList\"\n        units.filter.list = ['grid cells', 'map units']\n        units.value = 'grid cells'\n\n        zero_back = arcpy.Parameter(\n            displayName=\"Treat zero values as background?\",\n            name=\"zero_back\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, output, out_text, units, zero_back]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_text = parameters[2].valueAsText\n        units = parameters[3].valueAsText\n        zero_back = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_perimeter(i=i, output=output, out_text=out_text, units=units, zero_back=zero_back)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterStreamsToVector(object):\n    def __init__(self):\n        self.label = \"Raster Streams To Vector\"\n        self.description = \"Converts a raster stream file into a vector file.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [streams, d8_pntr, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        streams = parameters[0].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        d8_pntr = parameters[1].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_streams_to_vector(streams=streams, d8_pntr=d8_pntr, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterSummaryStats(object):\n    def __init__(self):\n        self.label = \"Raster Summary Stats\"\n        self.description = \"Measures a rasters min, max, average, standard deviation, num. non-nodata cells, and total.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_summary_stats(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterToVectorLines(object):\n    def __init__(self):\n        self.label = \"Raster To Vector Lines\"\n        self.description = \"Converts a raster lines features into a vector of the POLYLINE shapetype\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster Lines File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_to_vector_lines(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterToVectorPoints(object):\n    def __init__(self):\n        self.label = \"Raster To Vector Points\"\n        self.description = \"Converts a raster dataset to a vector of the POINT shapetype.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Points File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_to_vector_points(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterToVectorPolygons(object):\n    def __init__(self):\n        self.label = \"Raster To Vector Polygons\"\n        self.description = \"Converts a raster dataset to a vector of the POLYGON shapetype.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygons File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_to_vector_polygons(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterizeStreams(object):\n    def __init__(self):\n        self.label = \"Rasterize Streams\"\n        self.description = \"Rasterizes vector streams based on Lindsay (2016) method.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        streams = arcpy.Parameter(\n            displayName=\"Input Vector Streams File\",\n            name=\"streams\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        streams.filter.list = [\"Polyline\"]\n\n        base = arcpy.Parameter(\n            displayName=\"Input Base Raster File\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        nodata = arcpy.Parameter(\n            displayName=\"Use NoData value for background?\",\n            name=\"nodata\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        nodata.value = 'True'\n\n        feature_id = arcpy.Parameter(\n            displayName=\"Use feature number as output value?\",\n            name=\"feature_id\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        feature_id.value = 'False'\n\n        params = [streams, base, output, nodata, feature_id]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        streams = parameters[0].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        base = parameters[1].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        output = parameters[2].valueAsText\n        nodata = parameters[3].valueAsText\n        feature_id = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.rasterize_streams(streams=streams, base=base, output=output, nodata=nodata, feature_id=feature_id)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Reciprocal(object):\n    def __init__(self):\n        self.label = \"Reciprocal\"\n        self.description = \"Returns the reciprocal (i.e. 1 / z) of values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.reciprocal(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Reclass(object):\n    def __init__(self):\n        self.label = \"Reclass\"\n        self.description = \"Reclassifies the values in a raster image.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        reclass_vals = arcpy.Parameter(\n            displayName=\"Reclass Values (new value; from value; to less than)\",\n            name=\"reclass_vals\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        assign_mode = arcpy.Parameter(\n            displayName=\"Operate in assign mode? (i.e. Reclass data are pair values rather than triplets)\",\n            name=\"assign_mode\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, reclass_vals, assign_mode]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        reclass_vals = parameters[2].valueAsText\n        assign_mode = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.reclass(i=i, output=output, reclass_vals=reclass_vals, assign_mode=assign_mode)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ReclassEqualInterval(object):\n    def __init__(self):\n        self.label = \"Reclass Equal Interval\"\n        self.description = \"Reclassifies the values in a raster image based on equal-ranges.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        interval = arcpy.Parameter(\n            displayName=\"Class Interval Size\",\n            name=\"interval\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        interval.value = '10.0'\n\n        start_val = arcpy.Parameter(\n            displayName=\"Starting Value\",\n            name=\"start_val\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        end_val = arcpy.Parameter(\n            displayName=\"Ending Value\",\n            name=\"end_val\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, interval, start_val, end_val]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        interval = parameters[2].valueAsText\n        start_val = parameters[3].valueAsText\n        end_val = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.reclass_equal_interval(i=i, output=output, interval=interval, start_val=start_val, end_val=end_val)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ReclassFromFile(object):\n    def __init__(self):\n        self.label = \"Reclass From File\"\n        self.description = \"Reclassifies the values in a raster image using reclass ranges in a text file.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        reclass_file = arcpy.Parameter(\n            displayName=\"Input Reclass Text File\",\n            name=\"reclass_file\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, reclass_file, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        reclass_file = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.reclass_from_file(i=i, reclass_file=reclass_file, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ReconcileMultipleHeaders(object):\n    def __init__(self):\n        self.label = \"Reconcile Multiple Headers\"\n        self.description = \"This tool adjusts the crop yield values for data sets collected with multiple headers or combines.\"\n        self.category = \"Precision Agriculture\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Points\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        region_field = arcpy.Parameter(\n            displayName=\"Region Field Name\",\n            name=\"region_field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        region_field.parameterDependencies = [i.name]\n\n        yield_field = arcpy.Parameter(\n            displayName=\"Yield Field Name\",\n            name=\"yield_field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        yield_field.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Points\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius (m)\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        min_yield = arcpy.Parameter(\n            displayName=\"Minimum Yield\",\n            name=\"min_yield\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_yield = arcpy.Parameter(\n            displayName=\"Maximum Yield\",\n            name=\"max_yield\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        mean_tonnage = arcpy.Parameter(\n            displayName=\"Overall Average Tonnage (Optional)\",\n            name=\"mean_tonnage\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, region_field, yield_field, output, radius, min_yield, max_yield, mean_tonnage]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        region_field = parameters[1].valueAsText\n        yield_field = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        radius = parameters[4].valueAsText\n        min_yield = parameters[5].valueAsText\n        max_yield = parameters[6].valueAsText\n        mean_tonnage = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.reconcile_multiple_headers(i=i, region_field=region_field, yield_field=yield_field, output=output, radius=radius, min_yield=min_yield, max_yield=max_yield, mean_tonnage=mean_tonnage)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RecoverFlightlineInfo(object):\n    def __init__(self):\n        self.label = \"Recover Flightline Info\"\n        self.description = \"Associates LiDAR points by their flightlines.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR Points\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        max_time_diff = arcpy.Parameter(\n            displayName=\"Maximum In-Flightline Time Difference (seconds)\",\n            name=\"max_time_diff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_time_diff.value = '5.0'\n\n        pt_src_id = arcpy.Parameter(\n            displayName=\"Add flightline info to the Point Source ID?\",\n            name=\"pt_src_id\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        pt_src_id.value = 'False'\n\n        user_data = arcpy.Parameter(\n            displayName=\"Add flightline info to the User Data?\",\n            name=\"user_data\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        user_data.value = 'False'\n\n        rgb = arcpy.Parameter(\n            displayName=\"Add flightline info to the RGB colour data?\",\n            name=\"rgb\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        rgb.value = 'False'\n\n        params = [i, output, max_time_diff, pt_src_id, user_data, rgb]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        max_time_diff = parameters[2].valueAsText\n        pt_src_id = parameters[3].valueAsText\n        user_data = parameters[4].valueAsText\n        rgb = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.recover_flightline_info(i=i, output=output, max_time_diff=max_time_diff, pt_src_id=pt_src_id, user_data=user_data, rgb=rgb)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RecreatePassLines(object):\n    def __init__(self):\n        self.label = \"Recreate Pass Lines\"\n        self.description = \"This tool can be used to approximate the harvester pass lines from yield points.\"\n        self.category = \"Precision Agriculture\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Points\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        yield_field_name = arcpy.Parameter(\n            displayName=\"Yield Field Name\",\n            name=\"yield_field_name\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        yield_field_name.parameterDependencies = [i.name]\n\n        output_lines = arcpy.Parameter(\n            displayName=\"Output Pass Line\",\n            name=\"output_lines\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        output_points = arcpy.Parameter(\n            displayName=\"Output Points\",\n            name=\"output_points\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        max_change_in_heading = arcpy.Parameter(\n            displayName=\"Max Change In Heading (degrees)\",\n            name=\"max_change_in_heading\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_change_in_heading.value = '25.0'\n\n        ignore_zeros = arcpy.Parameter(\n            displayName=\"Ignore zero-valued yield points?\",\n            name=\"ignore_zeros\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        ignore_zeros.value = 'False'\n\n        params = [i, yield_field_name, output_lines, output_points, max_change_in_heading, ignore_zeros]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        yield_field_name = parameters[1].valueAsText\n        output_lines = parameters[2].valueAsText\n        output_points = parameters[3].valueAsText\n        max_change_in_heading = parameters[4].valueAsText\n        ignore_zeros = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.recreate_pass_lines(i=i, yield_field_name=yield_field_name, output_lines=output_lines, output_points=output_points, max_change_in_heading=max_change_in_heading, ignore_zeros=ignore_zeros)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ReinitializeAttributeTable(object):\n    def __init__(self):\n        self.label = \"Reinitialize Attribute Table\"\n        self.description = \"Reinitializes a vector's attribute table deleting all fields but the feature ID (FID).\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.reinitialize_attribute_table(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RelatedCircumscribingCircle(object):\n    def __init__(self):\n        self.label = \"Related Circumscribing Circle\"\n        self.description = \"Calculates the related circumscribing circle of vector polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.related_circumscribing_circle(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RelativeAspect(object):\n    def __init__(self):\n        self.label = \"Relative Aspect\"\n        self.description = \"Calculates relative aspect (relative to a user-specified direction) from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        azimuth = arcpy.Parameter(\n            displayName=\"Azimuth\",\n            name=\"azimuth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        azimuth.value = '0.0'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, azimuth, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        azimuth = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.relative_aspect(dem=dem, output=output, azimuth=azimuth, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RelativeTopographicPosition(object):\n    def __init__(self):\n        self.label = \"Relative Topographic Position\"\n        self.description = \"Calculates the relative topographic position index from a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [dem, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.relative_topographic_position(dem=dem, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RemoveFieldEdgePoints(object):\n    def __init__(self):\n        self.label = \"Remove Field Edge Points\"\n        self.description = \"This tool can be used to remove, or flag, most of the points along the edges from a crop yield data set.\"\n        self.category = \"Precision Agriculture\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Points\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Points\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        dist = arcpy.Parameter(\n            displayName=\"Average Distance Between Passes (m)\",\n            name=\"dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_change_in_heading = arcpy.Parameter(\n            displayName=\"Max Change In Heading (degrees)\",\n            name=\"max_change_in_heading\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_change_in_heading.value = '25.0'\n\n        flag_edges = arcpy.Parameter(\n            displayName=\"Don't remove edge points, just flag them?\",\n            name=\"flag_edges\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        flag_edges.value = 'False'\n\n        params = [i, output, dist, max_change_in_heading, flag_edges]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        dist = parameters[2].valueAsText\n        max_change_in_heading = parameters[3].valueAsText\n        flag_edges = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.remove_field_edge_points(i=i, output=output, dist=dist, max_change_in_heading=max_change_in_heading, flag_edges=flag_edges)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RemoveOffTerrainObjects(object):\n    def __init__(self):\n        self.label = \"Remove Off Terrain Objects\"\n        self.description = \"Removes off-terrain objects from a raster digital elevation model (DEM).\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Dimension\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        filter.value = '11'\n\n        slope = arcpy.Parameter(\n            displayName=\"Slope Threshold\",\n            name=\"slope\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        slope.value = '15.0'\n\n        params = [dem, output, filter, slope]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        slope = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.remove_off_terrain_objects(dem=dem, output=output, filter=filter, slope=slope)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RemovePolygonHoles(object):\n    def __init__(self):\n        self.label = \"Remove Polygon Holes\"\n        self.description = \"Removes holes within the features of a vector polygon file.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.remove_polygon_holes(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RemoveRasterPolygonHoles(object):\n    def __init__(self):\n        self.label = \"Remove Raster Polygon Holes\"\n        self.description = \"Removes polygon holes, or 'donut-holes', from raster polygons.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster Image\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        threshold = arcpy.Parameter(\n            displayName=\"Threshold Size (Grid Cells):\",\n            name=\"threshold\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        threshold.value = '3'\n\n        use_diagonals = arcpy.Parameter(\n            displayName=\"Use diagonal neighbours during clumping?\",\n            name=\"use_diagonals\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_diagonals.value = 'True'\n\n        params = [i, output, threshold, use_diagonals]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        threshold = parameters[2].valueAsText\n        use_diagonals = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.remove_raster_polygon_holes(i=i, output=output, threshold=threshold, use_diagonals=use_diagonals)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RemoveShortStreams(object):\n    def __init__(self):\n        self.label = \"Remove Short Streams\"\n        self.description = \"Removes short first-order streams from a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        min_length = arcpy.Parameter(\n            displayName=\"Minimum Tributary Length (map units)\",\n            name=\"min_length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, streams, output, min_length, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        min_length = parameters[3].valueAsText\n        esri_pntr = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.remove_short_streams(d8_pntr=d8_pntr, streams=streams, output=output, min_length=min_length, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RemoveSpurs(object):\n    def __init__(self):\n        self.label = \"Remove Spurs\"\n        self.description = \"Removes the spurs (pruning operation) from a Boolean line image; intended to be used on the output of the LineThinning tool.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        iterations = arcpy.Parameter(\n            displayName=\"Maximum Iterations\",\n            name=\"iterations\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        iterations.value = '10'\n\n        params = [i, output, iterations]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        iterations = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.remove_spurs(i=i, output=output, iterations=iterations)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RepairStreamVectorTopology(object):\n    def __init__(self):\n        self.label = \"Repair Stream Vector Topology\"\n        self.description = \"This tool resolves topological errors and inconsistencies associated with digitized vector streams.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Lines\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Lines\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        dist = arcpy.Parameter(\n            displayName=\"Snap Distance\",\n            name=\"dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        params = [i, output, dist]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        dist = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.repair_stream_vector_topology(i=i, output=output, dist=dist)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Resample(object):\n    def __init__(self):\n        self.label = \"Resample\"\n        self.description = \"Resamples one or more input images into a destination image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        method = arcpy.Parameter(\n            displayName=\"Resampling Method\",\n            name=\"method\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        method.filter.type = \"ValueList\"\n        method.filter.list = ['nn', 'bilinear', 'cc']\n        method.value = 'cc'\n\n        params = [inputs, output, cell_size, base, method]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        cell_size = parameters[2].valueAsText\n        base = parameters[3].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        method = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.resample(inputs=inputs, output=output, cell_size=cell_size, base=base, method=method)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RescaleValueRange(object):\n    def __init__(self):\n        self.label = \"Rescale Value Range\"\n        self.description = \"Performs a min-max contrast stretch on an input greytone image.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_min_val = arcpy.Parameter(\n            displayName=\"Output Raster Minimum Value\",\n            name=\"out_min_val\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_max_val = arcpy.Parameter(\n            displayName=\"Output Raster Maximum Value\",\n            name=\"out_max_val\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        clip_min = arcpy.Parameter(\n            displayName=\"Lower-Tail Clip Value (optional)\",\n            name=\"clip_min\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        clip_max = arcpy.Parameter(\n            displayName=\"Upper-Tail Clip Value (optional)\",\n            name=\"clip_max\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, out_min_val, out_max_val, clip_min, clip_max]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_min_val = parameters[2].valueAsText\n        out_max_val = parameters[3].valueAsText\n        clip_min = parameters[4].valueAsText\n        clip_max = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.rescale_value_range(i=i, output=output, out_min_val=out_min_val, out_max_val=out_max_val, clip_min=clip_min, clip_max=clip_max)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RgbToIhs(object):\n    def __init__(self):\n        self.label = \"Rgb To Ihs\"\n        self.description = \"Converts red, green, and blue (RGB) images into intensity, hue, and saturation (IHS) images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        red = arcpy.Parameter(\n            displayName=\"Input Red Band File (optional; only if colour-composite not specified)\",\n            name=\"red\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        green = arcpy.Parameter(\n            displayName=\"Input Green Band File (optional; only if colour-composite not specified)\",\n            name=\"green\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        blue = arcpy.Parameter(\n            displayName=\"Input Blue Band File (optional; only if colour-composite not specified)\",\n            name=\"blue\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        composite = arcpy.Parameter(\n            displayName=\"Input Colour-Composite Image File (optional; only if individual bands not specified)\",\n            name=\"composite\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        intensity = arcpy.Parameter(\n            displayName=\"Output Intensity File\",\n            name=\"intensity\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        intensity.filter.list = [\"tif\"]\n\n        hue = arcpy.Parameter(\n            displayName=\"Output Hue File\",\n            name=\"hue\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        hue.filter.list = [\"tif\"]\n\n        saturation = arcpy.Parameter(\n            displayName=\"Output Saturation File\",\n            name=\"saturation\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        saturation.filter.list = [\"tif\"]\n\n        params = [red, green, blue, composite, intensity, hue, saturation]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        red = parameters[0].valueAsText\n        if red is not None:\n            desc = arcpy.Describe(red)\n            red = desc.catalogPath\n        green = parameters[1].valueAsText\n        if green is not None:\n            desc = arcpy.Describe(green)\n            green = desc.catalogPath\n        blue = parameters[2].valueAsText\n        if blue is not None:\n            desc = arcpy.Describe(blue)\n            blue = desc.catalogPath\n        composite = parameters[3].valueAsText\n        if composite is not None:\n            desc = arcpy.Describe(composite)\n            composite = desc.catalogPath\n        intensity = parameters[4].valueAsText\n        hue = parameters[5].valueAsText\n        saturation = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.rgb_to_ihs(red=red, green=green, blue=blue, composite=composite, intensity=intensity, hue=hue, saturation=saturation)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Rho8FlowAccumulation(object):\n    def __init__(self):\n        self.label = \"Rho8 Flow Accumulation\"\n        self.description = \"Calculates Fairfield and Leymarie (1991) flow accumulation.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input DEM or Rho8 Pointer File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['cells', 'specific contributing area', 'catchment area']\n        out_type.value = 'specific contributing area'\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip the upper tail by 1%?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = 'False'\n\n        pntr = arcpy.Parameter(\n            displayName=\"Is the input raster a Rho8 flow pointer?\",\n            name=\"pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        pntr.value = 'False'\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"If a pointer is input, does it use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [i, output, out_type, log, clip, pntr, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_type = parameters[2].valueAsText\n        log = parameters[3].valueAsText\n        clip = parameters[4].valueAsText\n        pntr = parameters[5].valueAsText\n        esri_pntr = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.rho8_flow_accumulation(i=i, output=output, out_type=out_type, log=log, clip=clip, pntr=pntr, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Rho8Pointer(object):\n    def __init__(self):\n        self.label = \"Rho8 Pointer\"\n        self.description = \"Calculates a stochastic Rho8 flow pointer raster from an input DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Should the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [dem, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        esri_pntr = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.rho8_pointer(dem=dem, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RingCurvature(object):\n    def __init__(self):\n        self.label = \"Ring Curvature\"\n        self.description = \"This tool calculates ring curvature from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.ring_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RiverCenterlines(object):\n    def __init__(self):\n        self.label = \"River Centerlines\"\n        self.description = \"Maps river centerlines from an input water raster.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster Image\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector Lines File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        min_length = arcpy.Parameter(\n            displayName=\"Min. Line Length (In Grid Cells)\",\n            name=\"min_length\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_length.value = '3'\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius (In Grid Cells)\",\n            name=\"radius\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '4'\n\n        params = [i, output, min_length, radius]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        min_length = parameters[2].valueAsText\n        radius = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.river_centerlines(i=i, output=output, min_length=min_length, radius=radius)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RobertsCrossFilter(object):\n    def __init__(self):\n        self.label = \"Roberts Cross Filter\"\n        self.description = \"Performs a Robert's cross edge-detection filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        clip = arcpy.Parameter(\n            displayName=\"Distribution Tail Clip Amount (Percent)\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '0.0'\n\n        params = [i, output, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        clip = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.roberts_cross_filter(i=i, output=output, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RootMeanSquareError(object):\n    def __init__(self):\n        self.label = \"Root Mean Square Error\"\n        self.description = \"Calculates the RMSE and other accuracy statistics.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, base]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        base = parameters[1].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.root_mean_square_error(i=i, base=base)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Rotor(object):\n    def __init__(self):\n        self.label = \"Rotor\"\n        self.description = \"This tool calculates rotor from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.rotor(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Round(object):\n    def __init__(self):\n        self.label = \"Round\"\n        self.description = \"Rounds the values in an input raster to the nearest integer value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.round(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RuggednessIndex(object):\n    def __init__(self):\n        self.label = \"Ruggedness Index\"\n        self.description = \"Calculates the Riley et al.'s (1999) terrain ruggedness index from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.ruggedness_index(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ScharrFilter(object):\n    def __init__(self):\n        self.label = \"Scharr Filter\"\n        self.description = \"Performs a Scharr edge-detection filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        clip = arcpy.Parameter(\n            displayName=\"Distribution Tail Clip Amount (Percent)\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '0.0'\n\n        params = [i, output, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        clip = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.scharr_filter(i=i, output=output, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SedimentTransportIndex(object):\n    def __init__(self):\n        self.label = \"Sediment Transport Index\"\n        self.description = \"Calculates the sediment transport index.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        sca = arcpy.Parameter(\n            displayName=\"Input Specific Contributing Area (SCA) File\",\n            name=\"sca\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        slope = arcpy.Parameter(\n            displayName=\"Input Slope File\",\n            name=\"slope\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        sca_exponent = arcpy.Parameter(\n            displayName=\"Specific Contributing Area (SCA) Exponent\",\n            name=\"sca_exponent\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        sca_exponent.value = '0.4'\n\n        slope_exponent = arcpy.Parameter(\n            displayName=\"Slope Exponent\",\n            name=\"slope_exponent\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        slope_exponent.value = '1.3'\n\n        params = [sca, slope, output, sca_exponent, slope_exponent]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        sca = parameters[0].valueAsText\n        if sca is not None:\n            desc = arcpy.Describe(sca)\n            sca = desc.catalogPath\n        slope = parameters[1].valueAsText\n        if slope is not None:\n            desc = arcpy.Describe(slope)\n            slope = desc.catalogPath\n        output = parameters[2].valueAsText\n        sca_exponent = parameters[3].valueAsText\n        slope_exponent = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.sediment_transport_index(sca=sca, slope=slope, output=output, sca_exponent=sca_exponent, slope_exponent=slope_exponent)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SelectTilesByPolygon(object):\n    def __init__(self):\n        self.label = \"Select Tiles By Polygon\"\n        self.description = \"Copies LiDAR tiles overlapping with a polygon into an output directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        indir = arcpy.Parameter(\n            displayName=\"Input Directory\",\n            name=\"indir\",\n            datatype=\"DEFolder\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        outdir = arcpy.Parameter(\n            displayName=\"Output Directory\",\n            name=\"outdir\",\n            datatype=\"DEFolder\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        polygons = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"polygons\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        polygons.filter.list = [\"Polygon\"]\n\n        params = [indir, outdir, polygons]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        indir = parameters[0].valueAsText\n        outdir = parameters[1].valueAsText\n        polygons = parameters[2].valueAsText\n        if polygons is not None:\n            desc = arcpy.Describe(polygons)\n            polygons = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.select_tiles_by_polygon(indir=indir, outdir=outdir, polygons=polygons)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SetNodataValue(object):\n    def __init__(self):\n        self.label = \"Set Nodata Value\"\n        self.description = \"Assign the NoData value for an input image.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        back_value = arcpy.Parameter(\n            displayName=\"Background Value\",\n            name=\"back_value\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        back_value.value = '0.0'\n\n        params = [i, output, back_value]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        back_value = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.set_nodata_value(i=i, output=output, back_value=back_value)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ShadowAnimation(object):\n    def __init__(self):\n        self.label = \"Shadow Animation\"\n        self.description = \"This tool creates an animated GIF of shadows based on an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Digital Surface Model (DSM) Raster\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        palette = arcpy.Parameter(\n            displayName=\"DSM Palette\",\n            name=\"palette\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        palette.filter.type = \"ValueList\"\n        palette.filter.list = ['atlas', 'high_relief', 'arid', 'soft', 'muted', 'light_quant', 'purple', 'viridi', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep', 'none']\n        palette.value = 'atlas'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File (*.html)\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        max_dist = arcpy.Parameter(\n            displayName=\"Maximum Search Distance (xy units)\",\n            name=\"max_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        date = arcpy.Parameter(\n            displayName=\"Date (DD/MM/YYYY)\",\n            name=\"date\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        date.value = '21/06/2021'\n\n        interval = arcpy.Parameter(\n            displayName=\"Time Interval (in minutes)\",\n            name=\"interval\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        interval.value = '15'\n\n        location = arcpy.Parameter(\n            displayName=\"Lat/Long/UTC-offset (e.g. 43.5448/-80.2482/-4)\",\n            name=\"location\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        location.value = '43.5448/-80.2482/-4'\n\n        height = arcpy.Parameter(\n            displayName=\"Image Height (in pixels)\",\n            name=\"height\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        height.value = '600'\n\n        delay = arcpy.Parameter(\n            displayName=\"Delay (in milliseconds)\",\n            name=\"delay\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        delay.value = '250'\n\n        label = arcpy.Parameter(\n            displayName=\"Label text (blank for none)\",\n            name=\"label\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        params = [i, palette, output, max_dist, date, interval, location, height, delay, label]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        palette = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        max_dist = parameters[3].valueAsText\n        date = parameters[4].valueAsText\n        interval = parameters[5].valueAsText\n        location = parameters[6].valueAsText\n        height = parameters[7].valueAsText\n        delay = parameters[8].valueAsText\n        label = parameters[9].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.shadow_animation(i=i, palette=palette, output=output, max_dist=max_dist, date=date, interval=interval, location=location, height=height, delay=delay, label=label)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ShadowImage(object):\n    def __init__(self):\n        self.label = \"Shadow Image\"\n        self.description = \"This tool creates a raster of shadow areas based on an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Digital Surface Model (DSM) Raster\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        palette = arcpy.Parameter(\n            displayName=\"DSM Palette\",\n            name=\"palette\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        palette.filter.type = \"ValueList\"\n        palette.filter.list = ['atlas', 'high_relief', 'arid', 'soft', 'muted', 'light_quant', 'purple', 'viridis', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep', 'none']\n        palette.value = 'soft'\n\n        max_dist = arcpy.Parameter(\n            displayName=\"Maximum Search Distance (xy units)\",\n            name=\"max_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        date = arcpy.Parameter(\n            displayName=\"Date (DD/MM/YYYY)\",\n            name=\"date\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        date.value = '21/06/2021'\n\n        time = arcpy.Parameter(\n            displayName=\"Time (HH:MM, e.g. 03:15AM or 14:30)\",\n            name=\"time\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        time.value = '13:00'\n\n        location = arcpy.Parameter(\n            displayName=\"Lat/Long/UTC-offset (e.g. 43.5448/-80.2482/-4)\",\n            name=\"location\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        location.value = '43.5448/-80.2482/-4'\n\n        params = [i, output, palette, max_dist, date, time, location]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        palette = parameters[2].valueAsText\n        max_dist = parameters[3].valueAsText\n        date = parameters[4].valueAsText\n        time = parameters[5].valueAsText\n        location = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.shadow_image(i=i, output=output, palette=palette, max_dist=max_dist, date=date, time=time, location=location)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ShapeComplexityIndex(object):\n    def __init__(self):\n        self.label = \"Shape Complexity Index\"\n        self.description = \"Calculates overall polygon shape complexity or irregularity.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.shape_complexity_index(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ShapeComplexityIndexRaster(object):\n    def __init__(self):\n        self.label = \"Shape Complexity Index Raster\"\n        self.description = \"Calculates the complexity of raster polygons or classes.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.shape_complexity_index_raster(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ShapeIndex(object):\n    def __init__(self):\n        self.label = \"Shape Index\"\n        self.description = \"This tool calculates the shape index from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        zfactor = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.shape_index(dem=dem, output=output, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ShreveStreamMagnitude(object):\n    def __init__(self):\n        self.label = \"Shreve Stream Magnitude\"\n        self.description = \"Assigns the Shreve stream magnitude to each link in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.shreve_stream_magnitude(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SigmoidalContrastStretch(object):\n    def __init__(self):\n        self.label = \"Sigmoidal Contrast Stretch\"\n        self.description = \"Performs a sigmoidal contrast stretch on input images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        cutoff = arcpy.Parameter(\n            displayName=\"Cutoff Value (0.0 - 0.95)\",\n            name=\"cutoff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        cutoff.value = '0.0'\n\n        gain = arcpy.Parameter(\n            displayName=\"Gain Value\",\n            name=\"gain\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        gain.value = '1.0'\n\n        num_tones = arcpy.Parameter(\n            displayName=\"Number of Tones\",\n            name=\"num_tones\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_tones.value = '256'\n\n        params = [i, output, cutoff, gain, num_tones]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        cutoff = parameters[2].valueAsText\n        gain = parameters[3].valueAsText\n        num_tones = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.sigmoidal_contrast_stretch(i=i, output=output, cutoff=cutoff, gain=gain, num_tones=num_tones)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Sin(object):\n    def __init__(self):\n        self.label = \"Sin\"\n        self.description = \"Returns the sine (sin) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.sin(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SinglePartToMultiPart(object):\n    def __init__(self):\n        self.label = \"Single Part To Multi Part\"\n        self.description = \"Converts a vector file containing multi-part features into a vector containing only single-part features.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Line or Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        field = arcpy.Parameter(\n            displayName=\"Grouping ID Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Line or Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, field, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.single_part_to_multi_part(i=i, field=field, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Sinh(object):\n    def __init__(self):\n        self.label = \"Sinh\"\n        self.description = \"Returns the hyperbolic sine (sinh) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.sinh(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Sink(object):\n    def __init__(self):\n        self.label = \"Sink\"\n        self.description = \"Identifies the depressions in a DEM, giving each feature a unique identifier.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        input = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"input\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [input, output, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        zero_background = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.sink(i=i, output=output, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Slope(object):\n    def __init__(self):\n        self.label = \"Slope\"\n        self.description = \"Calculates a slope raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        units = arcpy.Parameter(\n            displayName=\"Units\",\n            name=\"units\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        units.filter.type = \"ValueList\"\n        units.filter.list = ['degrees', 'radians', 'percent']\n        units.value = 'degrees'\n\n        params = [dem, output, zfactor, units]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        zfactor = parameters[2].valueAsText\n        units = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.slope(dem=dem, output=output, zfactor=zfactor, units=units)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SlopeVsAspectPlot(object):\n    def __init__(self):\n        self.label = \"Slope Vs Aspect Plot\"\n        self.description = \"This tool creates a slope-aspect relation plot from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster Image\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File (*.html)\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        bin_size = arcpy.Parameter(\n            displayName=\"Aspect Bin Size (degrees)\",\n            name=\"bin_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        bin_size.value = '2.0'\n\n        min_slope = arcpy.Parameter(\n            displayName=\"Minimum Slope (degrees)\",\n            name=\"min_slope\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_slope.value = '0.1'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [i, output, bin_size, min_slope, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        bin_size = parameters[2].valueAsText\n        min_slope = parameters[3].valueAsText\n        zfactor = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.slope_vs_aspect_plot(i=i, output=output, bin_size=bin_size, min_slope=min_slope, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SlopeVsElevationPlot(object):\n    def __init__(self):\n        self.label = \"Slope Vs Elevation Plot\"\n        self.description = \"Creates a slope vs. elevation plot for one or more DEMs.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input DEM Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        watershed = arcpy.Parameter(\n            displayName=\"Input Watershed Files (optional)\",\n            name=\"watershed\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        watershed.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [inputs, watershed, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        watershed = parameters[1].valueAsText\n        if watershed is not None:\n            items = watershed.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            watershed = \";\".join(items_path)\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.slope_vs_elevation_plot(inputs=inputs, watershed=watershed, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SmoothVectors(object):\n    def __init__(self):\n        self.label = \"Smooth Vectors\"\n        self.description = \"Smooths a vector coverage of either a POLYLINE or POLYGON base ShapeType.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Size\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '3'\n\n        params = [i, output, filter]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.smooth_vectors(i=i, output=output, filter=filter)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SmoothVegetationResidual(object):\n    def __init__(self):\n        self.label = \"Smooth Vegetation Residual\"\n        self.description = \"This tool can smooth the residual roughness due to vegetation cover in LiDAR DEMs.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Digital Elevation Model (DEM) Raster\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        max_scale = arcpy.Parameter(\n            displayName=\"Maximum Search Neighbourhood Radius (grid cells)\",\n            name=\"max_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_scale.value = '30'\n\n        dev_threshold = arcpy.Parameter(\n            displayName=\"DEVmax Threshold\",\n            name=\"dev_threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        dev_threshold.value = '1.0'\n\n        scale_threshold = arcpy.Parameter(\n            displayName=\"DEVmax Scale Threshold\",\n            name=\"scale_threshold\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        scale_threshold.value = '5'\n\n        params = [i, output, max_scale, dev_threshold, scale_threshold]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        max_scale = parameters[2].valueAsText\n        dev_threshold = parameters[3].valueAsText\n        scale_threshold = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.smooth_vegetation_residual(i=i, output=output, max_scale=max_scale, dev_threshold=dev_threshold, scale_threshold=scale_threshold)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SnapPourPoints(object):\n    def __init__(self):\n        self.label = \"Snap Pour Points\"\n        self.description = \"Moves outlet points used to specify points of interest in a watershedding operation to the cell with the highest flow accumulation in its neighbourhood.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        pour_pts = arcpy.Parameter(\n            displayName=\"Input Pour Points (Outlet) File\",\n            name=\"pour_pts\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        pour_pts.filter.list = [\"Point\"]\n\n        flow_accum = arcpy.Parameter(\n            displayName=\"Input D8 Flow Accumulation File\",\n            name=\"flow_accum\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        snap_dist = arcpy.Parameter(\n            displayName=\"Maximum Snap Distance (map units)\",\n            name=\"snap_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [pour_pts, flow_accum, output, snap_dist]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        pour_pts = parameters[0].valueAsText\n        if pour_pts is not None:\n            desc = arcpy.Describe(pour_pts)\n            pour_pts = desc.catalogPath\n        flow_accum = parameters[1].valueAsText\n        if flow_accum is not None:\n            desc = arcpy.Describe(flow_accum)\n            flow_accum = desc.catalogPath\n        output = parameters[2].valueAsText\n        snap_dist = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.snap_pour_points(pour_pts=pour_pts, flow_accum=flow_accum, output=output, snap_dist=snap_dist)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SobelFilter(object):\n    def __init__(self):\n        self.label = \"Sobel Filter\"\n        self.description = \"Performs a Sobel edge-detection filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        variant = arcpy.Parameter(\n            displayName=\"Variant\",\n            name=\"variant\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        variant.filter.type = \"ValueList\"\n        variant.filter.list = ['3x3', '5x5']\n        variant.value = '3x3'\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip Tails (%)\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '0.0'\n\n        params = [i, output, variant, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        variant = parameters[2].valueAsText\n        clip = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.sobel_filter(i=i, output=output, variant=variant, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SortLidar(object):\n    def __init__(self):\n        self.label = \"Sort Lidar\"\n        self.description = \"Sorts LiDAR points based on their properties.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR Points\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        criteria = arcpy.Parameter(\n            displayName=\"Sort Criteria:\",\n            name=\"criteria\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        params = [i, output, criteria]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        criteria = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.sort_lidar(i=i, output=output, criteria=criteria)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SphericalStdDevOfNormals(object):\n    def __init__(self):\n        self.label = \"Spherical Std Dev Of Normals\"\n        self.description = \"Calculates the spherical standard deviation of surface normals for a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Dimension\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '11'\n\n        params = [dem, output, filter]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.spherical_std_dev_of_normals(dem=dem, output=output, filter=filter)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SplitColourComposite(object):\n    def __init__(self):\n        self.label = \"Split Colour Composite\"\n        self.description = \"Splits an RGB colour composite image into separate multispectral images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Colour Composite Image File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        red = arcpy.Parameter(\n            displayName=\"Output Red Band File\",\n            name=\"red\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        red.filter.list = [\"tif\"]\n\n        green = arcpy.Parameter(\n            displayName=\"Output Green Band File\",\n            name=\"green\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        green.filter.list = [\"tif\"]\n\n        blue = arcpy.Parameter(\n            displayName=\"Output Blue Band File\",\n            name=\"blue\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        blue.filter.list = [\"tif\"]\n\n        params = [i, red, green, blue]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        red = parameters[1].valueAsText\n        green = parameters[2].valueAsText\n        blue = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.split_colour_composite(i=i, red=red, green=green, blue=blue)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SplitLidar(object):\n    def __init__(self):\n        self.label = \"Split Lidar\"\n        self.description = \"Splits LiDAR points up into a series of new files based on their properties.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        criterion = arcpy.Parameter(\n            displayName=\"Split Criterion\",\n            name=\"criterion\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        criterion.filter.type = \"ValueList\"\n        criterion.filter.list = ['num_pts', 'x', 'y', 'z', 'intensity', 'class', 'user_data', 'point_source_id', 'scan_angle', 'time']\n        criterion.value = 'num_pts'\n\n        interval = arcpy.Parameter(\n            displayName=\"Interval\",\n            name=\"interval\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_pts = arcpy.Parameter(\n            displayName=\"Minimum Number of Points\",\n            name=\"min_pts\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_pts.value = '5'\n\n        params = [i, criterion, interval, min_pts]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        criterion = parameters[1].valueAsText\n        interval = parameters[2].valueAsText\n        min_pts = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.split_lidar(i=i, criterion=criterion, interval=interval, min_pts=min_pts)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SplitVectorLines(object):\n    def __init__(self):\n        self.label = \"Split Vector Lines\"\n        self.description = \"Used to split a vector line coverage into even-lengthed segments.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Lines\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Lines\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        length = arcpy.Parameter(\n            displayName=\"Max Segment Length\",\n            name=\"length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, length]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        length = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.split_vector_lines(i=i, output=output, length=length)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SplitWithLines(object):\n    def __init__(self):\n        self.label = \"Split With Lines\"\n        self.description = \"Splits the lines or polygons in one layer using the lines in another layer.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Lines or Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        split = arcpy.Parameter(\n            displayName=\"Input Vector Lines File\",\n            name=\"split\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        split.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, split, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        split = parameters[1].valueAsText\n        if split is not None:\n            desc = arcpy.Describe(split)\n            split = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.split_with_lines(i=i, split=split, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Square(object):\n    def __init__(self):\n        self.label = \"Square\"\n        self.description = \"Squares the values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.square(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SquareRoot(object):\n    def __init__(self):\n        self.label = \"Square Root\"\n        self.description = \"Returns the square root of the values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.square_root(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StandardDeviationContrastStretch(object):\n    def __init__(self):\n        self.label = \"Standard Deviation Contrast Stretch\"\n        self.description = \"Performs a standard-deviation contrast stretch on input images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        stdev = arcpy.Parameter(\n            displayName=\"Standard Deviation Threshold\",\n            name=\"stdev\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        stdev.value = '2.0'\n\n        num_tones = arcpy.Parameter(\n            displayName=\"Number of Tones\",\n            name=\"num_tones\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_tones.value = '256'\n\n        params = [i, output, stdev, num_tones]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        stdev = parameters[2].valueAsText\n        num_tones = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.standard_deviation_contrast_stretch(i=i, output=output, stdev=stdev, num_tones=num_tones)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StandardDeviationFilter(object):\n    def __init__(self):\n        self.label = \"Standard Deviation Filter\"\n        self.description = \"Assigns each cell in the output grid the standard deviation of values in a moving window centred on each grid cell in the input raster.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.standard_deviation_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StandardDeviationOfSlope(object):\n    def __init__(self):\n        self.label = \"Standard Deviation Of Slope\"\n        self.description = \"Calculates the standard deviation of slope from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, zfactor, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        zfactor = parameters[2].valueAsText\n        filterx = parameters[3].valueAsText\n        filtery = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.standard_deviation_of_slope(i=i, output=output, zfactor=zfactor, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StochasticDepressionAnalysis(object):\n    def __init__(self):\n        self.label = \"Stochastic Depression Analysis\"\n        self.description = \"Performs a stochastic analysis of depressions within a DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        rmse = arcpy.Parameter(\n            displayName=\"DEM root-mean-square-error (z units)\",\n            name=\"rmse\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        range = arcpy.Parameter(\n            displayName=\"Range of Autocorrelation (map units)\",\n            name=\"range\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        iterations = arcpy.Parameter(\n            displayName=\"Iterations\",\n            name=\"iterations\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        iterations.value = '100'\n\n        params = [dem, output, rmse, range, iterations]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        rmse = parameters[2].valueAsText\n        range = parameters[3].valueAsText\n        iterations = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.stochastic_depression_analysis(dem=dem, output=output, rmse=rmse, range=range, iterations=iterations)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StrahlerOrderBasins(object):\n    def __init__(self):\n        self.label = \"Strahler Order Basins\"\n        self.description = \"Identifies Strahler-order basins from an input stream network.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, streams, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.strahler_order_basins(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StrahlerStreamOrder(object):\n    def __init__(self):\n        self.label = \"Strahler Stream Order\"\n        self.description = \"Assigns the Strahler stream order to each link in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.strahler_stream_order(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StreamLinkClass(object):\n    def __init__(self):\n        self.label = \"Stream Link Class\"\n        self.description = \"Identifies the exterior/interior links and nodes in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.stream_link_class(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StreamLinkIdentifier(object):\n    def __init__(self):\n        self.label = \"Stream Link Identifier\"\n        self.description = \"Assigns a unique identifier to each link in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.stream_link_identifier(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StreamLinkLength(object):\n    def __init__(self):\n        self.label = \"Stream Link Length\"\n        self.description = \"Estimates the length of each link (or tributary) in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        linkid = arcpy.Parameter(\n            displayName=\"Input Stream Link (Tributary) ID File\",\n            name=\"linkid\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, linkid, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        linkid = parameters[1].valueAsText\n        if linkid is not None:\n            desc = arcpy.Describe(linkid)\n            linkid = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.stream_link_length(d8_pntr=d8_pntr, linkid=linkid, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StreamLinkSlope(object):\n    def __init__(self):\n        self.label = \"Stream Link Slope\"\n        self.description = \"Estimates the average slope of each link (or tributary) in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        linkid = arcpy.Parameter(\n            displayName=\"Input Stream Link (Tributary) ID File\",\n            name=\"linkid\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, linkid, dem, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        linkid = parameters[1].valueAsText\n        if linkid is not None:\n            desc = arcpy.Describe(linkid)\n            linkid = desc.catalogPath\n        dem = parameters[2].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[3].valueAsText\n        esri_pntr = parameters[4].valueAsText\n        zero_background = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.stream_link_slope(d8_pntr=d8_pntr, linkid=linkid, dem=dem, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StreamPowerIndex(object):\n    def __init__(self):\n        self.label = \"Stream Power Index\"\n        self.description = \"Calculates the relative stream power index.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        sca = arcpy.Parameter(\n            displayName=\"Input Specific Contributing Area (SCA) File\",\n            name=\"sca\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        slope = arcpy.Parameter(\n            displayName=\"Input Slope File\",\n            name=\"slope\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        exponent = arcpy.Parameter(\n            displayName=\"Specific Contributing Area (SCA) Exponent\",\n            name=\"exponent\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        exponent.value = '1.0'\n\n        params = [sca, slope, output, exponent]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        sca = parameters[0].valueAsText\n        if sca is not None:\n            desc = arcpy.Describe(sca)\n            sca = desc.catalogPath\n        slope = parameters[1].valueAsText\n        if slope is not None:\n            desc = arcpy.Describe(slope)\n            slope = desc.catalogPath\n        output = parameters[2].valueAsText\n        exponent = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.stream_power_index(sca=sca, slope=slope, output=output, exponent=exponent)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StreamSlopeContinuous(object):\n    def __init__(self):\n        self.label = \"Stream Slope Continuous\"\n        self.description = \"Estimates the slope of each grid cell in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, dem, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        dem = parameters[2].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[3].valueAsText\n        esri_pntr = parameters[4].valueAsText\n        zero_background = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.stream_slope_continuous(d8_pntr=d8_pntr, streams=streams, dem=dem, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Subbasins(object):\n    def __init__(self):\n        self.label = \"Subbasins\"\n        self.description = \"Identifies the catchments, or sub-basin, draining to each link in a stream network.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, streams, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.subbasins(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Subtract(object):\n    def __init__(self):\n        self.label = \"Subtract\"\n        self.description = \"Performs a differencing operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.subtract(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SumOverlay(object):\n    def __init__(self):\n        self.label = \"Sum Overlay\"\n        self.description = \"Calculates the sum for each grid cell from a group of raster images.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.sum_overlay(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SurfaceAreaRatio(object):\n    def __init__(self):\n        self.label = \"Surface Area Ratio\"\n        self.description = \"Calculates a the surface area ratio of each grid cell in an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.surface_area_ratio(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SvmClassification(object):\n    def __init__(self):\n        self.label = \"Svm Classification\"\n        self.description = \"Performs an SVM binary classification using training site polygons/points and multiple input images.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Predictor Rasters\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        scaling = arcpy.Parameter(\n            displayName=\"Scaling Method\",\n            name=\"scaling\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        scaling.filter.type = \"ValueList\"\n        scaling.filter.list = ['None', 'Normalize', 'Standardize']\n        scaling.value = 'Normalize'\n\n        training = arcpy.Parameter(\n            displayName=\"Input Training Polygons/Points\",\n            name=\"training\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        field = arcpy.Parameter(\n            displayName=\"Class Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [training.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        c = arcpy.Parameter(\n            displayName=\"c-Value\",\n            name=\"c\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        c.value = '200.0'\n\n        gamma = arcpy.Parameter(\n            displayName=\"Kernel Gamma\",\n            name=\"gamma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        gamma.value = '50.0'\n\n        tolerance = arcpy.Parameter(\n            displayName=\"Tolerance\",\n            name=\"tolerance\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        tolerance.value = '0.1'\n\n        test_proportion = arcpy.Parameter(\n            displayName=\"Test Proportion\",\n            name=\"test_proportion\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        test_proportion.value = '0.2'\n\n        params = [inputs, scaling, training, field, output, c, gamma, tolerance, test_proportion]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        scaling = parameters[1].valueAsText\n        training = parameters[2].valueAsText\n        if training is not None:\n            desc = arcpy.Describe(training)\n            training = desc.catalogPath\n        field = parameters[3].valueAsText\n        output = parameters[4].valueAsText\n        c = parameters[5].valueAsText\n        gamma = parameters[6].valueAsText\n        tolerance = parameters[7].valueAsText\n        test_proportion = parameters[8].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.svm_classification(inputs=inputs, scaling=scaling, training=training, field=field, output=output, c=c, gamma=gamma, tolerance=tolerance, test_proportion=test_proportion)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SvmRegression(object):\n    def __init__(self):\n        self.label = \"Svm Regression\"\n        self.description = \"Performs a supervised SVM regression analysis using training site points and predictor rasters.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Predictor Rasters\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        scaling = arcpy.Parameter(\n            displayName=\"Scaling Method\",\n            name=\"scaling\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        scaling.filter.type = \"ValueList\"\n        scaling.filter.list = ['None', 'Normalize', 'Standardize']\n        scaling.value = 'Normalize'\n\n        training = arcpy.Parameter(\n            displayName=\"Input Training Polygons/Points\",\n            name=\"training\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        training.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Class Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [training.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        c = arcpy.Parameter(\n            displayName=\"c-Value\",\n            name=\"c\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        c.value = '50.0'\n\n        eps = arcpy.Parameter(\n            displayName=\"Epsilon Value\",\n            name=\"eps\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        eps.value = '10.0'\n\n        gamma = arcpy.Parameter(\n            displayName=\"Kernel Gamma\",\n            name=\"gamma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        gamma.value = '0.5'\n\n        test_proportion = arcpy.Parameter(\n            displayName=\"Test Proportion\",\n            name=\"test_proportion\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        test_proportion.value = '0.2'\n\n        params = [inputs, scaling, training, field, output, c, eps, gamma, test_proportion]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        scaling = parameters[1].valueAsText\n        training = parameters[2].valueAsText\n        if training is not None:\n            desc = arcpy.Describe(training)\n            training = desc.catalogPath\n        field = parameters[3].valueAsText\n        output = parameters[4].valueAsText\n        c = parameters[5].valueAsText\n        eps = parameters[6].valueAsText\n        gamma = parameters[7].valueAsText\n        test_proportion = parameters[8].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.svm_regression(inputs=inputs, scaling=scaling, training=training, field=field, output=output, c=c, eps=eps, gamma=gamma, test_proportion=test_proportion)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SymmetricalDifference(object):\n    def __init__(self):\n        self.label = \"Symmetrical Difference\"\n        self.description = \"Outputs the features that occur in one of the two vector inputs but not both, i.e. no overlapping features.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        overlay = arcpy.Parameter(\n            displayName=\"Input Overlay Vector File\",\n            name=\"overlay\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        snap = arcpy.Parameter(\n            displayName=\"Snap Tolerance\",\n            name=\"snap\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        snap.value = '0.0'\n\n        params = [i, overlay, output, snap]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        overlay = parameters[1].valueAsText\n        if overlay is not None:\n            desc = arcpy.Describe(overlay)\n            overlay = desc.catalogPath\n        output = parameters[2].valueAsText\n        snap = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.symmetrical_difference(i=i, overlay=overlay, output=output, snap=snap)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TinGridding(object):\n    def __init__(self):\n        self.label = \"Tin Gridding\"\n        self.description = \"Creates a raster grid based on a triangular irregular network (TIN) fitted to vector points.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        use_z = arcpy.Parameter(\n            displayName=\"Use Shapefile 'z' values?\",\n            name=\"use_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_z.value = 'False'\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_triangle_edge_length = arcpy.Parameter(\n            displayName=\"Maximum Triangle Edge Length (optional)\",\n            name=\"max_triangle_edge_length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, use_z, output, resolution, base, max_triangle_edge_length]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        use_z = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        resolution = parameters[4].valueAsText\n        base = parameters[5].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        max_triangle_edge_length = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.tin_gridding(i=i, field=field, use_z=use_z, output=output, resolution=resolution, base=base, max_triangle_edge_length=max_triangle_edge_length)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Tan(object):\n    def __init__(self):\n        self.label = \"Tan\"\n        self.description = \"Returns the tangent (tan) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.tan(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TangentialCurvature(object):\n    def __init__(self):\n        self.label = \"Tangential Curvature\"\n        self.description = \"Calculates a tangential curvature raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.tangential_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Tanh(object):\n    def __init__(self):\n        self.label = \"Tanh\"\n        self.description = \"Returns the hyperbolic tangent (tanh) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.tanh(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ThickenRasterLine(object):\n    def __init__(self):\n        self.label = \"Thicken Raster Line\"\n        self.description = \"Thickens single-cell wide lines within a raster image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.thicken_raster_line(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TimeInDaylight(object):\n    def __init__(self):\n        self.label = \"Time In Daylight\"\n        self.description = \"Calculates the proportion of time a location is not within an area of shadow.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        az_fraction = arcpy.Parameter(\n            displayName=\"Azimuth Fraction\",\n            name=\"az_fraction\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        az_fraction.value = '10.0'\n\n        max_dist = arcpy.Parameter(\n            displayName=\"Maximum Search Distance\",\n            name=\"max_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        max_dist.value = '100.0'\n\n        lat = arcpy.Parameter(\n            displayName=\"Centre Point Latitude\",\n            name=\"lat\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        long = arcpy.Parameter(\n            displayName=\"Centre Point Longitude\",\n            name=\"long\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        utc_offset = arcpy.Parameter(\n            displayName=\"UTC Offset (e.g. -04:00, +06:00)\",\n            name=\"utc_offset\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        utc_offset.value = '00:00'\n\n        start_day = arcpy.Parameter(\n            displayName=\"Start Day Of The Year (1-365)\",\n            name=\"start_day\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        start_day.value = '1'\n\n        end_day = arcpy.Parameter(\n            displayName=\"End Day Of The Year (1-365)\",\n            name=\"end_day\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        end_day.value = '365'\n\n        start_time = arcpy.Parameter(\n            displayName=\"Starting Hour (24-hour time: HH:MM:SS e.g. 05:00:00)\",\n            name=\"start_time\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        start_time.value = '00:00:00'\n\n        end_time = arcpy.Parameter(\n            displayName=\"Ending Hour (24-hour time: HH:MM:SS e.g. 21:00:00)\",\n            name=\"end_time\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        end_time.value = '23:59:59'\n\n        params = [dem, output, az_fraction, max_dist, lat, long, utc_offset, start_day, end_day, start_time, end_time]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        az_fraction = parameters[2].valueAsText\n        max_dist = parameters[3].valueAsText\n        lat = parameters[4].valueAsText\n        long = parameters[5].valueAsText\n        utc_offset = parameters[6].valueAsText\n        start_day = parameters[7].valueAsText\n        end_day = parameters[8].valueAsText\n        start_time = parameters[9].valueAsText\n        end_time = parameters[10].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.time_in_daylight(dem=dem, output=output, az_fraction=az_fraction, max_dist=max_dist, lat=lat, long=long, utc_offset=utc_offset, start_day=start_day, end_day=end_day, start_time=start_time, end_time=end_time)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ToDegrees(object):\n    def __init__(self):\n        self.label = \"To Degrees\"\n        self.description = \"Converts a raster from radians to degrees.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.to_degrees(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ToRadians(object):\n    def __init__(self):\n        self.label = \"To Radians\"\n        self.description = \"Converts a raster from degrees to radians.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.to_radians(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TophatTransform(object):\n    def __init__(self):\n        self.label = \"Tophat Transform\"\n        self.description = \"Performs either a white or black top-hat transform on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        variant = arcpy.Parameter(\n            displayName=\"Variant\",\n            name=\"variant\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        variant.filter.type = \"ValueList\"\n        variant.filter.list = ['white', 'black']\n        variant.value = 'white'\n\n        params = [i, output, filterx, filtery, variant]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        variant = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.tophat_transform(i=i, output=output, filterx=filterx, filtery=filtery, variant=variant)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TopoRender(object):\n    def __init__(self):\n        self.label = \"Topo Render\"\n        self.description = \"This tool creates a pseudo-3D rendering from an input DEM, for the purpose of effective topographic visualization.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Digital Elevation Model (DEM) Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        palette = arcpy.Parameter(\n            displayName=\"Palette\",\n            name=\"palette\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        palette.filter.type = \"ValueList\"\n        palette.filter.list = ['atlas', 'high_relief', 'arid', 'soft', 'earthtones', 'muted', 'light_quant', 'purple', 'viridis', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep', 'imhof', 'white']\n        palette.value = 'soft'\n\n        rev_palette = arcpy.Parameter(\n            displayName=\"Reverse the palette?\",\n            name=\"rev_palette\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        rev_palette.value = 'False'\n\n        az = arcpy.Parameter(\n            displayName=\"Light Source Direction (degrees)\",\n            name=\"az\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        az.value = '315.0'\n\n        alt = arcpy.Parameter(\n            displayName=\"Light Source Altitude (degrees)\",\n            name=\"alt\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        alt.value = '30.0'\n\n        background_hgt_offset = arcpy.Parameter(\n            displayName=\"Offset Height of Background (z-units)\",\n            name=\"background_hgt_offset\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        background_hgt_offset.value = '10.0'\n\n        polygon = arcpy.Parameter(\n            displayName=\"Clipping Polygon\",\n            name=\"polygon\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        polygon.filter.list = [\"Polygon\"]\n\n        background_clr = arcpy.Parameter(\n            displayName=\"Background RGB colour\",\n            name=\"background_clr\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        background_clr.value = '[255, 255, 255]'\n\n        attenuation = arcpy.Parameter(\n            displayName=\"Attenuation Parameter\",\n            name=\"attenuation\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        attenuation.value = '0.6'\n\n        ambient_light = arcpy.Parameter(\n            displayName=\"Ambient Light\",\n            name=\"ambient_light\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        ambient_light.value = '0.2'\n\n        z_factor = arcpy.Parameter(\n            displayName=\"Elevation Multiplier\",\n            name=\"z_factor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        z_factor.value = '1.0'\n\n        params = [dem, output, palette, rev_palette, az, alt, background_hgt_offset, polygon, background_clr, attenuation, ambient_light, z_factor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        palette = parameters[2].valueAsText\n        rev_palette = parameters[3].valueAsText\n        az = parameters[4].valueAsText\n        alt = parameters[5].valueAsText\n        background_hgt_offset = parameters[6].valueAsText\n        polygon = parameters[7].valueAsText\n        if polygon is not None:\n            desc = arcpy.Describe(polygon)\n            polygon = desc.catalogPath\n        background_clr = parameters[8].valueAsText\n        attenuation = parameters[9].valueAsText\n        ambient_light = parameters[10].valueAsText\n        z_factor = parameters[11].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.topo_render(dem=dem, output=output, palette=palette, rev_palette=rev_palette, az=az, alt=alt, background_hgt_offset=background_hgt_offset, polygon=polygon, background_clr=background_clr, attenuation=attenuation, ambient_light=ambient_light, z_factor=z_factor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TopographicPositionAnimation(object):\n    def __init__(self):\n        self.label = \"Topographic Position Animation\"\n        self.description = \"This tool creates an animated GIF of multi-scale local topographic position (elevation deviation).\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Digital Elevation Model (DEM) Raster\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        palette = arcpy.Parameter(\n            displayName=\"Palette\",\n            name=\"palette\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        palette.filter.type = \"ValueList\"\n        palette.filter.list = ['bl_yl_rd', 'bl_w_rd', 'purple', 'gn_yl', 'pi_y_g', 'viridis']\n        palette.value = 'bl_yl_rd'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File (*.html)\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_scale.value = '1'\n\n        num_steps = arcpy.Parameter(\n            displayName=\"Number of Steps\",\n            name=\"num_steps\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_steps.value = '100'\n\n        step_nonlinearity = arcpy.Parameter(\n            displayName=\"Step Nonlinearity\",\n            name=\"step_nonlinearity\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step_nonlinearity.value = '1.5'\n\n        height = arcpy.Parameter(\n            displayName=\"Image Height (in pixels)\",\n            name=\"height\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        height.value = '600'\n\n        delay = arcpy.Parameter(\n            displayName=\"Delay (in milliseconds)\",\n            name=\"delay\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        delay.value = '250'\n\n        label = arcpy.Parameter(\n            displayName=\"Label text (blank for none)\",\n            name=\"label\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        dev_max = arcpy.Parameter(\n            displayName=\"Use DEVmax for topo position?\",\n            name=\"dev_max\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        dev_max.value = 'False'\n\n        params = [i, palette, output, min_scale, num_steps, step_nonlinearity, height, delay, label, dev_max]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        palette = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        num_steps = parameters[4].valueAsText\n        step_nonlinearity = parameters[5].valueAsText\n        height = parameters[6].valueAsText\n        delay = parameters[7].valueAsText\n        label = parameters[8].valueAsText\n        dev_max = parameters[9].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.topographic_position_animation(i=i, palette=palette, output=output, min_scale=min_scale, num_steps=num_steps, step_nonlinearity=step_nonlinearity, height=height, delay=delay, label=label, dev_max=dev_max)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TopologicalStreamOrder(object):\n    def __init__(self):\n        self.label = \"Topological Stream Order\"\n        self.description = \"Assigns each link in a stream network its topological order.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.topological_stream_order(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TotalCurvature(object):\n    def __init__(self):\n        self.label = \"Total Curvature\"\n        self.description = \"Calculates a total curvature raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.total_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TotalFilter(object):\n    def __init__(self):\n        self.label = \"Total Filter\"\n        self.description = \"Performs a total filter on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.total_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TraceDownslopeFlowpaths(object):\n    def __init__(self):\n        self.label = \"Trace Downslope Flowpaths\"\n        self.description = \"Traces downslope flowpaths from one or more target sites (i.e. seed points).\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        seed_pts = arcpy.Parameter(\n            displayName=\"Input Vector Seed Points File\",\n            name=\"seed_pts\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        seed_pts.filter.list = [\"Point\"]\n\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [seed_pts, d8_pntr, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        seed_pts = parameters[0].valueAsText\n        if seed_pts is not None:\n            desc = arcpy.Describe(seed_pts)\n            seed_pts = desc.catalogPath\n        d8_pntr = parameters[1].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.trace_downslope_flowpaths(seed_pts=seed_pts, d8_pntr=d8_pntr, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TravellingSalesmanProblem(object):\n    def __init__(self):\n        self.label = \"Travelling Salesman Problem\"\n        self.description = \"Finds approximate solutions to travelling salesman problems, the goal of which is to identify the shortest route connecting a set of locations.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Points\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Lines\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        duration = arcpy.Parameter(\n            displayName=\"Max Duration\",\n            name=\"duration\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        duration.value = '60'\n\n        params = [i, output, duration]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        duration = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.travelling_salesman_problem(i=i, output=output, duration=duration)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TrendSurface(object):\n    def __init__(self):\n        self.label = \"Trend Surface\"\n        self.description = \"Estimates the trend surface of an input raster file.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        order = arcpy.Parameter(\n            displayName=\"Polynomial Order\",\n            name=\"order\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        order.value = '1'\n\n        params = [i, output, order]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        order = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.trend_surface(i=i, output=output, order=order)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TrendSurfaceVectorPoints(object):\n    def __init__(self):\n        self.label = \"Trend Surface Vector Points\"\n        self.description = \"Estimates a trend surface from vector points.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        order = arcpy.Parameter(\n            displayName=\"Polynomial Order\",\n            name=\"order\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        order.value = '1'\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, field, output, order, cell_size]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        order = parameters[3].valueAsText\n        cell_size = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.trend_surface_vector_points(i=i, field=field, output=output, order=order, cell_size=cell_size)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TributaryIdentifier(object):\n    def __init__(self):\n        self.label = \"Tributary Identifier\"\n        self.description = \"Assigns a unique identifier to each tributary in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.tributary_identifier(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Truncate(object):\n    def __init__(self):\n        self.label = \"Truncate\"\n        self.description = \"Truncates the values in a raster to the desired number of decimal places.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        num_decimals = arcpy.Parameter(\n            displayName=\"Number of Decimals After Truncation\",\n            name=\"num_decimals\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, num_decimals]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        num_decimals = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.truncate(i=i, output=output, num_decimals=num_decimals)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TurningBandsSimulation(object):\n    def __init__(self):\n        self.label = \"Turning Bands Simulation\"\n        self.description = \"Creates an image containing random values based on a turning-bands simulation.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        base = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        range = arcpy.Parameter(\n            displayName=\"Range of Autocorrelation (map units)\",\n            name=\"range\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        iterations = arcpy.Parameter(\n            displayName=\"Iterations\",\n            name=\"iterations\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        iterations.value = '1000'\n\n        params = [base, output, range, iterations]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        base = parameters[0].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        output = parameters[1].valueAsText\n        range = parameters[2].valueAsText\n        iterations = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.turning_bands_simulation(base=base, output=output, range=range, iterations=iterations)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TwoSampleKsTest(object):\n    def __init__(self):\n        self.label = \"Two Sample Ks Test\"\n        self.description = \"Performs a 2-sample K-S test for significant differences on two input rasters.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"First Input File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Second Input File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        num_samples = arcpy.Parameter(\n            displayName=\"Num. Samples (blank for while image)\",\n            name=\"num_samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [input1, input2, output, num_samples]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        num_samples = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.two_sample_ks_test(input1=input1, input2=input2, output=output, num_samples=num_samples)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Union(object):\n    def __init__(self):\n        self.label = \"Union\"\n        self.description = \"Splits vector layers at their overlaps, creating a layer containing all the portions from both input and overlay layers.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        overlay = arcpy.Parameter(\n            displayName=\"Input Overlay Vector File\",\n            name=\"overlay\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        snap = arcpy.Parameter(\n            displayName=\"Snap Tolerance\",\n            name=\"snap\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        snap.value = '0.0'\n\n        params = [i, overlay, output, snap]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        overlay = parameters[1].valueAsText\n        if overlay is not None:\n            desc = arcpy.Describe(overlay)\n            overlay = desc.catalogPath\n        output = parameters[2].valueAsText\n        snap = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.union(i=i, overlay=overlay, output=output, snap=snap)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass UnnestBasins(object):\n    def __init__(self):\n        self.label = \"Unnest Basins\"\n        self.description = \"Extract whole watersheds for a set of outlet points.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        pour_pts = arcpy.Parameter(\n            displayName=\"Input Pour Points (Outlet) File\",\n            name=\"pour_pts\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        pour_pts.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, pour_pts, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        pour_pts = parameters[1].valueAsText\n        if pour_pts is not None:\n            desc = arcpy.Describe(pour_pts)\n            pour_pts = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.unnest_basins(d8_pntr=d8_pntr, pour_pts=pour_pts, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass UnsharpMasking(object):\n    def __init__(self):\n        self.label = \"Unsharp Masking\"\n        self.description = \"An image sharpening technique that enhances edges.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        sigma = arcpy.Parameter(\n            displayName=\"Standard Deviation (pixels)\",\n            name=\"sigma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma.value = '0.75'\n\n        amount = arcpy.Parameter(\n            displayName=\"Amount (%)\",\n            name=\"amount\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        amount.value = '100.0'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Threshold\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        threshold.value = '0.0'\n\n        params = [i, output, sigma, amount, threshold]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        sigma = parameters[2].valueAsText\n        amount = parameters[3].valueAsText\n        threshold = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.unsharp_masking(i=i, output=output, sigma=sigma, amount=amount, threshold=threshold)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Unsphericity(object):\n    def __init__(self):\n        self.label = \"Unsphericity\"\n        self.description = \"This tool calculates the unsphericity curvature from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.unsphericity(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass UpdateNodataCells(object):\n    def __init__(self):\n        self.label = \"Update Nodata Cells\"\n        self.description = \"Replaces the NoData values in an input raster with the corresponding values contained in a second update layer.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File 1\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File 2 (Update Layer)\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.update_nodata_cells(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass UpslopeDepressionStorage(object):\n    def __init__(self):\n        self.label = \"Upslope Depression Storage\"\n        self.description = \"Estimates the average upslope depression storage depth.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.upslope_depression_storage(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass UserDefinedWeightsFilter(object):\n    def __init__(self):\n        self.label = \"User Defined Weights Filter\"\n        self.description = \"Performs a user-defined weights filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        weights = arcpy.Parameter(\n            displayName=\"Input Weights File\",\n            name=\"weights\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        weights.filter.list = [\"csv\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        center = arcpy.Parameter(\n            displayName=\"Kernel Center\",\n            name=\"center\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        center.filter.type = \"ValueList\"\n        center.filter.list = ['center', 'upper-left', 'upper-right', 'lower-left', 'lower-right']\n        center.value = 'center'\n\n        normalize = arcpy.Parameter(\n            displayName=\"Normalize kernel weights?\",\n            name=\"normalize\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        normalize.value = 'False'\n\n        params = [i, weights, output, center, normalize]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        weights = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        center = parameters[3].valueAsText\n        normalize = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.user_defined_weights_filter(i=i, weights=weights, output=output, center=center, normalize=normalize)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass VectorHexBinning(object):\n    def __init__(self):\n        self.label = \"Vector Hex Binning\"\n        self.description = \"Hex-bins a set of vector points.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        width = arcpy.Parameter(\n            displayName=\"Hexagon Width\",\n            name=\"width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        orientation = arcpy.Parameter(\n            displayName=\"Grid Orientation\",\n            name=\"orientation\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        orientation.filter.type = \"ValueList\"\n        orientation.filter.list = ['horizontal', 'vertical']\n        orientation.value = 'horizontal'\n\n        params = [i, output, width, orientation]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        width = parameters[2].valueAsText\n        orientation = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.vector_hex_binning(i=i, output=output, width=width, orientation=orientation)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass VectorLinesToRaster(object):\n    def __init__(self):\n        self.label = \"Vector Lines To Raster\"\n        self.description = \"Converts a vector containing polylines into a raster.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Lines File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polyline\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n        field.value = 'FID'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        nodata = arcpy.Parameter(\n            displayName=\"Background value is NoData?\",\n            name=\"nodata\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        nodata.value = 'True'\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, output, nodata, cell_size, base]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        nodata = parameters[3].valueAsText\n        cell_size = parameters[4].valueAsText\n        base = parameters[5].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.vector_lines_to_raster(i=i, field=field, output=output, nodata=nodata, cell_size=cell_size, base=base)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass VectorPointsToRaster(object):\n    def __init__(self):\n        self.label = \"Vector Points To Raster\"\n        self.description = \"Converts a vector containing points into a raster.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n        field.value = 'FID'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        assign = arcpy.Parameter(\n            displayName=\"Assignment Operation\",\n            name=\"assign\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        assign.filter.type = \"ValueList\"\n        assign.filter.list = ['first', 'last', 'min', 'max', 'sum', 'number']\n        assign.value = 'last'\n\n        nodata = arcpy.Parameter(\n            displayName=\"Background value is NoData?\",\n            name=\"nodata\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        nodata.value = 'True'\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, output, assign, nodata, cell_size, base]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        assign = parameters[3].valueAsText\n        nodata = parameters[4].valueAsText\n        cell_size = parameters[5].valueAsText\n        base = parameters[6].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.vector_points_to_raster(i=i, field=field, output=output, assign=assign, nodata=nodata, cell_size=cell_size, base=base)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass VectorPolygonsToRaster(object):\n    def __init__(self):\n        self.label = \"Vector Polygons To Raster\"\n        self.description = \"Converts a vector containing polygons into a raster.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n        field.value = 'FID'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        nodata = arcpy.Parameter(\n            displayName=\"Background value is NoData?\",\n            name=\"nodata\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        nodata.value = 'True'\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, output, nodata, cell_size, base]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        nodata = parameters[3].valueAsText\n        cell_size = parameters[4].valueAsText\n        base = parameters[5].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.vector_polygons_to_raster(i=i, field=field, output=output, nodata=nodata, cell_size=cell_size, base=base)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass VectorStreamNetworkAnalysis(object):\n    def __init__(self):\n        self.label = \"Vector Stream Network Analysis\"\n        self.description = \"This tool performs common stream network analysis operations on an input vector stream file.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams Vector\",\n            name=\"streams\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        streams.filter.list = [\"Polyline\"]\n\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Lines\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        cutting_height = arcpy.Parameter(\n            displayName=\"Maximum Ridge-cutting Height (z units)\",\n            name=\"cutting_height\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        cutting_height.value = '10.0'\n\n        snap = arcpy.Parameter(\n            displayName=\"Snap Distance\",\n            name=\"snap\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        snap.value = '0.1'\n\n        params = [streams, dem, output, cutting_height, snap]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        streams = parameters[0].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        dem = parameters[1].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[2].valueAsText\n        cutting_height = parameters[3].valueAsText\n        snap = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.vector_stream_network_analysis(streams=streams, dem=dem, output=output, cutting_height=cutting_height, snap=snap)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass VerticalExcessCurvature(object):\n    def __init__(self):\n        self.label = \"Vertical Excess Curvature\"\n        self.description = \"This tool calculates vertical excess curvature from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.vertical_excess_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Viewshed(object):\n    def __init__(self):\n        self.label = \"Viewshed\"\n        self.description = \"Identifies the viewshed for a point or set of points.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        stations = arcpy.Parameter(\n            displayName=\"Viewing Station Vector File\",\n            name=\"stations\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        stations.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        height = arcpy.Parameter(\n            displayName=\"Station Height (in z units)\",\n            name=\"height\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        height.value = '2.0'\n\n        params = [dem, stations, output, height]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        stations = parameters[1].valueAsText\n        if stations is not None:\n            desc = arcpy.Describe(stations)\n            stations = desc.catalogPath\n        output = parameters[2].valueAsText\n        height = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.viewshed(dem=dem, stations=stations, output=output, height=height)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass VisibilityIndex(object):\n    def __init__(self):\n        self.label = \"Visibility Index\"\n        self.description = \"Estimates the relative visibility of sites in a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        height = arcpy.Parameter(\n            displayName=\"Station Height (in z units)\",\n            name=\"height\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        height.value = '2.0'\n\n        res_factor = arcpy.Parameter(\n            displayName=\"Resolution Factor\",\n            name=\"res_factor\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        res_factor.value = '2'\n\n        params = [dem, output, height, res_factor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        height = parameters[2].valueAsText\n        res_factor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.visibility_index(dem=dem, output=output, height=height, res_factor=res_factor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass VoronoiDiagram(object):\n    def __init__(self):\n        self.label = \"Voronoi Diagram\"\n        self.description = \"Creates a vector Voronoi diagram for a set of vector points.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.voronoi_diagram(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Watershed(object):\n    def __init__(self):\n        self.label = \"Watershed\"\n        self.description = \"Identifies the watershed, or drainage basin, draining to a set of target cells.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        pour_pts = arcpy.Parameter(\n            displayName=\"Input Pour Points (Outlet) File\",\n            name=\"pour_pts\",\n            datatype=[\"DERasterDataset\", \"DEShapefile\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, pour_pts, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        pour_pts = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.watershed(d8_pntr=d8_pntr, pour_pts=pour_pts, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass WeightedOverlay(object):\n    def __init__(self):\n        self.label = \"Weighted Overlay\"\n        self.description = \"Performs a weighted sum on multiple input rasters after converting each image to a common scale. The tool performs a multi-criteria evaluation (MCE).\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        factors = arcpy.Parameter(\n            displayName=\"Input Factor Files\",\n            name=\"factors\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        factors.multiValue = True\n\n        weights = arcpy.Parameter(\n            displayName=\"Weight Values (e.g. 1.7;3.5;1.2)\",\n            name=\"weights\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        cost = arcpy.Parameter(\n            displayName=\"Cost Factor? (e.g. false;true;true)\",\n            name=\"cost\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        constraints = arcpy.Parameter(\n            displayName=\"Input Constraints Files\",\n            name=\"constraints\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        constraints.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        scale_max = arcpy.Parameter(\n            displayName=\"Suitability Scale Maximum\",\n            name=\"scale_max\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        scale_max.value = '1.0'\n\n        params = [factors, weights, cost, constraints, output, scale_max]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        factors = parameters[0].valueAsText\n        if factors is not None:\n            items = factors.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            factors = \";\".join(items_path)\n        weights = parameters[1].valueAsText\n        cost = parameters[2].valueAsText\n        constraints = parameters[3].valueAsText\n        if constraints is not None:\n            items = constraints.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            constraints = \";\".join(items_path)\n        output = parameters[4].valueAsText\n        scale_max = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.weighted_overlay(factors=factors, weights=weights, cost=cost, constraints=constraints, output=output, scale_max=scale_max)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass WeightedSum(object):\n    def __init__(self):\n        self.label = \"Weighted Sum\"\n        self.description = \"Performs a weighted-sum overlay on multiple input raster images.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        weights = arcpy.Parameter(\n            displayName=\"Weight Values (e.g. 1.7;3.5;1.2)\",\n            name=\"weights\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, weights, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        weights = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.weighted_sum(inputs=inputs, weights=weights, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass WetnessIndex(object):\n    def __init__(self):\n        self.label = \"Wetness Index\"\n        self.description = \"Calculates the topographic wetness index, Ln(A / tan(slope)).\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        sca = arcpy.Parameter(\n            displayName=\"Input Specific Contributing Area (SCA) File\",\n            name=\"sca\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        slope = arcpy.Parameter(\n            displayName=\"Input Slope File\",\n            name=\"slope\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [sca, slope, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        sca = parameters[0].valueAsText\n        if sca is not None:\n            desc = arcpy.Describe(sca)\n            sca = desc.catalogPath\n        slope = parameters[1].valueAsText\n        if slope is not None:\n            desc = arcpy.Describe(slope)\n            slope = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.wetness_index(sca=sca, slope=slope, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass WilcoxonSignedRankTest(object):\n    def __init__(self):\n        self.label = \"Wilcoxon Signed Rank Test\"\n        self.description = \"Performs a 2-sample K-S test for significant differences on two input rasters.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"First Input File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Second Input File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        num_samples = arcpy.Parameter(\n            displayName=\"Num. Samples (blank for while image)\",\n            name=\"num_samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [input1, input2, output, num_samples]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        num_samples = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.wilcoxon_signed_rank_test(input1=input1, input2=input2, output=output, num_samples=num_samples)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass WriteFunctionMemoryInsertion(object):\n    def __init__(self):\n        self.label = \"Write Function Memory Insertion\"\n        self.description = \"Performs a write function memory insertion for single-band multi-date change detection.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"First Date Input File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Second Date Input File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input3 = arcpy.Parameter(\n            displayName=\"Third Date Input File (Optional)\",\n            name=\"input3\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, input3, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        input3 = parameters[2].valueAsText\n        if input3 is not None:\n            desc = arcpy.Describe(input3)\n            input3 = desc.catalogPath\n        output = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.write_function_memory_insertion(input1=input1, input2=input2, input3=input3, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Xor(object):\n    def __init__(self):\n        self.label = \"Xor\"\n        self.description = \"Performs a logical XOR operator on two Boolean raster images.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.xor(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass YieldFilter(object):\n    def __init__(self):\n        self.label = \"Yield Filter\"\n        self.description = \"Filters crop yield values of point data derived from combine harvester yield monitors.\"\n        self.category = \"Precision Agriculture\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Points\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        yield_field = arcpy.Parameter(\n            displayName=\"Yield Field Name\",\n            name=\"yield_field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        yield_field.parameterDependencies = [i.name]\n\n        pass_field = arcpy.Parameter(\n            displayName=\"Pass Field Name\",\n            name=\"pass_field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        pass_field.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Points\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        width = arcpy.Parameter(\n            displayName=\"Swath Width\",\n            name=\"width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        width.value = '6.096'\n\n        z_score_threshold = arcpy.Parameter(\n            displayName=\"Z-score Threshold Value\",\n            name=\"z_score_threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        z_score_threshold.value = '2.5'\n\n        min_yield = arcpy.Parameter(\n            displayName=\"Minimum Yield\",\n            name=\"min_yield\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_yield.value = '0.0'\n\n        max_yield = arcpy.Parameter(\n            displayName=\"Maximum Yield\",\n            name=\"max_yield\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_yield.value = '99999.9'\n\n        params = [i, yield_field, pass_field, output, width, z_score_threshold, min_yield, max_yield]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        yield_field = parameters[1].valueAsText\n        pass_field = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        width = parameters[4].valueAsText\n        z_score_threshold = parameters[5].valueAsText\n        min_yield = parameters[6].valueAsText\n        max_yield = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.yield_filter(i=i, yield_field=yield_field, pass_field=pass_field, output=output, width=width, z_score_threshold=z_score_threshold, min_yield=min_yield, max_yield=max_yield)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass YieldMap(object):\n    def __init__(self):\n        self.label = \"Yield Map\"\n        self.description = \"This tool can be used to create a segmented-vector polygon yield map from a set of harvester points.\"\n        self.category = \"Precision Agriculture\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Points\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        pass_field_name = arcpy.Parameter(\n            displayName=\"Pass Field Name\",\n            name=\"pass_field_name\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        pass_field_name.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector Polygons\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        width = arcpy.Parameter(\n            displayName=\"Swath Width\",\n            name=\"width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        width.value = '6.096'\n\n        max_change_in_heading = arcpy.Parameter(\n            displayName=\"Max Change In Heading (degrees)\",\n            name=\"max_change_in_heading\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_change_in_heading.value = '25.0'\n\n        params = [i, pass_field_name, output, width, max_change_in_heading]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        pass_field_name = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        width = parameters[3].valueAsText\n        max_change_in_heading = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.yield_map(i=i, pass_field_name=pass_field_name, output=output, width=width, max_change_in_heading=max_change_in_heading)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass YieldNormalization(object):\n    def __init__(self):\n        self.label = \"Yield Normalization\"\n        self.description = \"This tool can be used to normalize the yield points for a field.\"\n        self.category = \"Precision Agriculture\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Points\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        yield_field = arcpy.Parameter(\n            displayName=\"Yield Field Name\",\n            name=\"yield_field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        yield_field.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Points\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        standardize = arcpy.Parameter(\n            displayName=\"Standardize rather than normalize?\",\n            name=\"standardize\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        standardize.value = 'False'\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius (m)\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        min_yield = arcpy.Parameter(\n            displayName=\"Minimum Yield\",\n            name=\"min_yield\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_yield.value = '0.0'\n\n        max_yield = arcpy.Parameter(\n            displayName=\"Maximum Yield\",\n            name=\"max_yield\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_yield.value = '99999.9'\n\n        params = [i, yield_field, output, standardize, radius, min_yield, max_yield]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        yield_field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        standardize = parameters[3].valueAsText\n        radius = parameters[4].valueAsText\n        min_yield = parameters[5].valueAsText\n        max_yield = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.yield_normalization(i=i, yield_field=yield_field, output=output, standardize=standardize, radius=radius, min_yield=min_yield, max_yield=max_yield)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ZScores(object):\n    def __init__(self):\n        self.label = \"Z Scores\"\n        self.description = \"Standardizes the values in an input raster by converting to z-scores.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.z_scores(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ZlidarToLas(object):\n    def __init__(self):\n        self.label = \"Zlidar To Las\"\n        self.description = \"Converts one or more zlidar files into the LAS data format.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input ZLidar Files\",\n            name=\"inputs\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        inputs.multiValue = True\n        inputs.filter.list = [\"las\", \"zip\"]\n\n        outdir = arcpy.Parameter(\n            displayName=\"Output Directory\",\n            name=\"outdir\",\n            datatype=\"DEFolder\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [inputs, outdir]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        outdir = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.zlidar_to_las(inputs=inputs, outdir=outdir)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ZonalStatistics(object):\n    def __init__(self):\n        self.label = \"Zonal Statistics\"\n        self.description = \"Extracts descriptive statistics for a group of patches in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Data File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        features = arcpy.Parameter(\n            displayName=\"Input Feature Definition File\",\n            name=\"features\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        stat = arcpy.Parameter(\n            displayName=\"Statistic Type\",\n            name=\"stat\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        stat.filter.type = \"ValueList\"\n        stat.filter.list = ['mean', 'median', 'minimum', 'maximum', 'range', 'standard deviation', 'total']\n        stat.value = 'mean'\n\n        out_table = arcpy.Parameter(\n            displayName=\"Output HTML Table File\",\n            name=\"out_table\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_table.filter.list = [\"html\"]\n\n        params = [i, features, output, stat, out_table]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        features = parameters[1].valueAsText\n        if features is not None:\n            desc = arcpy.Describe(features)\n            features = desc.catalogPath\n        output = parameters[2].valueAsText\n        stat = parameters[3].valueAsText\n        out_table = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.zonal_statistics(i=i, features=features, output=output, stat=stat, out_table=out_table)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\n"
  },
  {
    "path": "WBT/PRE/automation.py",
    "content": "##################################################################\n# Steps for updating WhiteboxTools-ArcGIS\n# Step 0: - Update the whitebox_tools.json file in the whiteboxgui repository\n# Step 1 - Delete the existing develop branch: git branch -D develop\n# Step 2 - Create a new develop branch: git checkout -b develop\n# Step 3 - Delete the old WhiteboxTools_win_amd64.zip in the root folder if needed\n# Step 4 - Run automation.py\n# Step 5 - Commit and push changes\n# Step 6 - Merge pull request on GitHub\n# Step 7 - Switch to master branch and pull updates: git checkout master | git pull\n##################################################################\n\nimport json\nimport os\nimport re\nimport shutil\nimport sys\nimport whitebox\nimport urllib.request\nfrom zipfile import ZipFile\nfrom urllib.request import urlopen\n\nwbt = whitebox.WhiteboxTools()\n\n\ndef to_camelcase(name):\n    \"\"\"\n    Convert snake_case name to CamelCase name\n    \"\"\"\n    return \"\".join(x.title() for x in name.split(\"_\"))\n\n\ndef to_label(name):\n    \"\"\"\n    Convert snake_case name to Title case label\n    \"\"\"\n    return \" \".join(x.title() for x in name.split(\"_\"))\n\n\ndef to_snakecase(name):\n    \"\"\"\n    Convert CamelCase name to snake_case name\n    \"\"\"\n    s1 = re.sub(\"(.)([A-Z][a-z]+)\", r\"\\1_\\2\", name)\n    return re.sub(\"([a-z0-9])([A-Z])\", r\"\\1_\\2\", s1).lower()\n\n\ndef write_header(file_path, tool_list):\n    \"\"\"\n    Generate Python script header for ArcGIS Python Toolbox\n    \"\"\"\n    f_header = open(file_path, \"w\")\n    f_header.write(\"import arcpy\\n\")\n    f_header.write(\"import os\\n\")\n    f_header.write(\"import webbrowser\\n\")\n    f_header.write(\"from WBT.whitebox_tools import WhiteboxTools\\n\")\n    f_header.write(\"if sys.version_info < (3, 0):\\n\")\n    f_header.write(\"    from StringIO import StringIO\\n\")\n    f_header.write(\"else:\\n\")\n    f_header.write(\"    from io import StringIO\\n\\n\")\n    f_header.write(\"wbt = WhiteboxTools()\\n\")\n    # ValueList (Dropdown List) for About WhiteboxTools functions (e.g., Run Tool, View Code)\n    f_header.write(\"tool_labels = []\\n\\n\")\n    tool_list.sort()\n    for tool in tool_list:\n        f_header.write('tool_labels.append(\"{}\")\\n'.format(tool))\n    f_header.write(\"\\n\\n\")\n    f_header.close()\n\n\ndef get_wbt_dict():\n    \"\"\"Generate a dictionary containing information for all tools.\n\n    Returns:\n        dict: The dictionary containing information for all tools.\n    \"\"\"\n\n    url = \"https://github.com/opengeos/whiteboxgui/raw/master/whiteboxgui/data/whitebox_tools.json\"\n    response = urlopen(url)\n    wbt_dict = json.loads(response.read())\n\n    return wbt_dict\n\n\ndef generate_tool_template(tool):\n    \"\"\"\n    Generate function block of each tool for the toolbox\n    \"\"\"\n    tool_params = []\n    for index, item in enumerate(tool[\"parameters\"]):\n        if index < 0:\n            tool_params.append(item)\n        else:\n            item_dup = \"{}={}\".format(item, item)\n            tool_params.append(item_dup)\n\n    lines = []\n    lines.append(\"class {}(object):\\n\".format(tool[\"name\"]))\n    lines.append(\"    def __init__(self):\\n\")\n    lines.append('        self.label = \"{}\"\\n'.format(tool[\"label\"]))\n    lines.append('        self.description = \"{}\"\\n'.format(\n        tool[\"description\"]))\n    lines.append('        self.category = \"{}\"\\n\\n'.format(tool[\"category\"]))\n    lines.append(\"    def getParameterInfo(self):\\n\")\n    # Loop through parameters\n    lines.append(define_tool_params(tool[\"parameters\"]))\n    lines.append(\"        return params\\n\\n\")\n    lines.append(\"    def updateParameters(self, parameters):\\n\")\n    lines.append(\"        return\\n\\n\")\n    lines.append(\"    def updateMessages(self, parameters):\\n\")\n    lines.append(\"        for param in parameters:\\n\")\n    lines.append(\"            param_str = param.valueAsText\\n\")\n    lines.append(\"            if param_str is not None:\\n\")\n    lines.append(\"                try:\\n\")\n    lines.append(\"                    desc = arcpy.Describe(param_str)\\n\")\n    lines.append(\n        '                    if (\".gdb\\\\\\\\\" in desc.catalogPath) or (\".mdb\\\\\\\\\" in desc.catalogPath):\\n'\n    )\n    lines.append(\n        '                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\\n'\n    )\n    lines.append(\"                except:\\n\")\n    lines.append(\"                    param.clearMessage()\\n\")\n    lines.append(\"        return\\n\\n\")\n    lines.append(\"    def execute(self, parameters, messages):\\n\")\n    # Access parameters through parameters[x].valueAsText\n    lines.append(define_execute(tool[\"parameters\"]))\n    # redirect standard output to tool dialogue\n    lines.append(\"        old_stdout = sys.stdout\\n\")\n    lines.append(\"        result = StringIO()\\n\")\n    lines.append(\"        sys.stdout = result\\n\")\n\n    # line = '        wbt.{}({})\\n'.format(to_snakecase(tool['name']), ', '.join(tool['parameters']).replace(\", class,\", \", cls,\"))\n    line = \"        wbt.{}({})\\n\".format(\n        to_snakecase(tool[\"name\"]),\n        \", \".join(tool_params).replace(\", class=class,\",\n                                       \", cls=cls,\").replace(\"input=input\", \"i=i\"),\n    )\n\n    # Deal with name conflict with reserved Python functions (and, or, not)\n    if tool[\"name\"] == \"And\":\n        line = line.replace(\"and\", \"And\")\n    elif tool[\"name\"] == \"Or\":\n        line = line.replace(\"or\", \"Or\")\n    elif tool[\"name\"] == \"Not\":\n        line = line.replace(\"not\", \"Not\")\n    lines.append(line)\n    lines.append(\"        sys.stdout = old_stdout\\n\")\n    lines.append(\"        result_string = result.getvalue()\\n\")\n    lines.append(\"        messages.addMessage(result_string)\\n\")\n    lines.append(\"        return\\n\\n\\n\")\n    return lines\n\n\ndef define_tool_params(params):\n    \"\"\"\n    Generate function block for each tool parameter\n    \"\"\"\n    lines = []\n    for param in params:\n        items = params[param]\n        if items[\"optional\"]:\n            parameter_type = \"Optional\"\n        else:\n            parameter_type = \"Required\"\n\n        if \"NewFile\" in items[\"parameter_type\"]:\n            direction = \"Output\"\n        else:\n            direction = \"Input\"\n\n        if param == \"class\":  # parameter cannot use Python reserved keyword\n            param = \"cls\"\n\n        data_type = get_data_type(items[\"parameter_type\"])\n\n        # if data_type['multi_value'] and param == \"i\":\n        #     param = \"inputs\"\n\n        if data_type[\"data_type\"] == '\"DERasterDataset\"' and direction == \"Output\":\n            data_type[\"data_type\"] = '\"DEFile\"'\n            data_type[\"data_filter\"] = '[\"tif\"]'\n            # if a filter is used, the parameter must be changed to required.\n            parameter_type = \"Required\"\n        elif data_type[\"data_type\"] == '\"DERasterDataset\"' and direction == \"Input\":\n            data_type[\"data_type\"] = '\"GPRasterLayer\"'\n        elif data_type[\"data_type\"] == '\"DEShapefile\"' and direction == \"Input\":\n            data_type[\"data_type\"] = '\"GPFeatureLayer\"'\n        elif (\n            data_type[\"data_type\"] == '[\"DERasterDataset\", \"GPDouble\"]'\n            and direction == \"Input\"\n        ):\n            data_type[\"data_type\"] = '[\"GPRasterLayer\", \"GPDouble\"]'\n\n        if data_type[\"data_filter\"] == '[\"html\"]':\n            parameter_type = \"Required\"\n\n        lines.append(\"        {} = arcpy.Parameter(\\n\".format(param))\n        lines.append('            displayName=\"{}\",\\n'.format(items[\"name\"]))\n        lines.append('            name=\"{}\",\\n'.format(param))\n        lines.append(\"            datatype={},\\n\".format(\n            data_type[\"data_type\"]))\n        lines.append(\n            '            parameterType=\"{}\",\\n'.format(parameter_type))\n        lines.append('            direction=\"{}\")\\n'.format(direction))\n\n        if data_type[\"multi_value\"]:\n            lines.append(\"        {}.multiValue = True\\n\".format(param))\n\n        if len(data_type[\"dependency_field\"]) > 0:\n            if data_type[\"dependency_field\"] == \"input\":\n                data_type[\"dependency_field\"] = \"i\"\n            lines.append(\n                \"        {}.parameterDependencies = [{}.name]\\n\".format(\n                    param, data_type[\"dependency_field\"]\n                )\n            )\n\n        if data_type[\"data_filter\"] != \"[]\":\n            if data_type[\"filter_type\"] == '\"ValueList\"':\n                lines.append(\n                    '        {}.filter.type = \"ValueList\"\\n'.format(param))\n\n            if (\n                data_type[\"data_filter\"]\n                in ['[\"Point\"]', '[\"Polyline\"]', '[\"Polygon\"]', '[\"las\", \"zip\"]']\n            ) and direction == \"Output\":\n                pass\n            else:\n                lines.append(\n                    \"        {}.filter.list = {}\\n\".format(\n                        param, data_type[\"data_filter\"]\n                    )\n                )\n\n        if items[\"default_value\"] is not None:\n            if (items[\"default_value\"] != \"null\") and (len(items[\"default_value\"]) > 0):\n                if \"false\" in items[\"default_value\"]:\n                    items[\"default_value\"] = False\n                elif \"true\" in items[\"default_value\"]:\n                    items[\"default_value\"] = True\n\n                lines.append(\n                    \"        {}.value = '{}'\\n\\n\".format(\n                        param, items[\"default_value\"])\n                )\n        else:\n            lines.append(\"\\n\")\n\n    line = \"        params = [{}]\\n\\n\".format(\", \".join(params))\n    if \"class\" in line:\n        line = line.replace(\", class,\", \", cls,\")\n\n    lines.append(line)\n    lines = \"\".join(lines)\n    return lines\n\n\ndef define_execute(params):\n    \"\"\"\n    Accessing tool parameters\n    \"\"\"\n    lines = []\n    for index, param in enumerate(params):\n        # get the full path to a input raster or vector layer\n        param_type = params[param][\"parameter_type\"]\n        inputRasVec = []\n        inputRasVec.append({\"ExistingFile\": \"Raster\"})\n        # inputRasVec.append({'ExistingFileOrFloat': 'Raster'})\n        inputRasVec.append({\"ExistingFile\": {\"Vector\": \"Point\"}})\n        inputRasVec.append({\"ExistingFile\": {\"Vector\": \"Line\"}})\n        inputRasVec.append({\"ExistingFile\": {\"Vector\": \"Polygon\"}})\n        inputRasVec.append({\"ExistingFile\": {\"Vector\": \"LineOrPolygon\"}})\n        inputRasVec.append({\"ExistingFile\": {\"Vector\": \"Any\"}})\n\n        optional = False\n\n        if \"optional\" in params[param].keys():\n            if params[param][\"optional\"] == \"true\":\n                optional = True\n\n        # deal with multi-value input\n        items = params[param]\n        data_type = get_data_type(items[\"parameter_type\"])\n        # if data_type['multi_value'] and param == 'i':\n        #     param = \"inputs\"\n\n        if param == \"class\":\n            param = \"cls\"\n\n        if param == \"input\":\n            param = \"i\"\n\n        # deal with multi-value inputs\n        lines.append(\n            \"        {} = parameters[{}].valueAsText\\n\".format(param, index))\n        if data_type[\"multi_value\"]:\n            lines.append(\"        if {} is not None:\\n\".format(param))\n            lines.append('            items = {}.split(\";\")\\n'.format(param))\n            lines.append(\"            items_path = []\\n\")\n            lines.append(\"            for item in items:\\n\")\n            lines.append(\n                \"                items_path.append(arcpy.Describe(item).catalogPath)\\n\"\n            )\n            lines.append(\n                '            {} = \";\".join(items_path)\\n'.format(param))\n\n        if param_type in inputRasVec:\n            #     lines.append('        desc = arcpy.Describe({})\\n'.format(param))\n            #     lines.append('        {} = desc.catalogPath\\n'.format(param))\n            # if param_type == \"Optional\":\n            lines.append(\"        if {} is not None:\\n\".format(param))\n            lines.append(\n                \"            desc = arcpy.Describe({})\\n\".format(param))\n            lines.append(\"            {} = desc.catalogPath\\n\".format(param))\n        elif param_type == {\"ExistingFileOrFloat\": \"Raster\"}:\n            lines.append(\"        if {} is not None:\\n\".format(param))\n            lines.append(\"            try:\\n\")\n            lines.append(\n                \"                {} = str(float({}))\\n\".format(param, param))\n            lines.append(\"            except:\\n\")\n            lines.append(\n                \"                desc = arcpy.Describe({})\\n\".format(param))\n            lines.append(\n                \"                {} = desc.catalogPath\\n\".format(param))\n\n            # lines.append('        if ({} is not None) and {}.isnumeric() == False:\\n'.format(param, param))\n\n        # if param == \"cell_size\":\n        #     print(param)\n\n        # if param_type in inputRasVec:\n        #     lines.append('        if {} is not None:\\n'.format(param))\n        #     lines.append('            desc = arcpy.Describe({})\\n'.format(param))\n        #     lines.append('            {} = desc.catalogPath\\n'.format(param))\n        #     lines.append('            if (\".gdb\\\\\\\\\" in desc.catalogPath) or (\".mdb\\\\\\\\\" in desc.catalogPath):\\n')\n        #     lines.append('                 arcpy.AddError(\"Datasets stored in a Geodatabase are not supported.\")\\n')\n        # elif optional:\n        #     lines.append('        if {} is None:\\n'.format(param))\n        #     lines.append('            {} = None\\n'.format(param))\n\n    lines = \"\".join(lines)\n    return lines\n\n\ndef get_data_type(param):\n    \"\"\"\n    Convert WhiteboxTools data types to ArcGIS data types\n    \"\"\"\n    data_type = '\"GPString\"'  # default data type\n    data_filter = \"[]\"  # https://goo.gl/EaVNzg\n    filter_type = '\"\"'\n    multi_value = False\n    dependency_field = \"\"\n\n    # ArcGIS data types: https://goo.gl/95JtFu\n    data_types = {\n        \"Boolean\": '\"GPBoolean\"',\n        \"Integer\": '\"GPLong\"',\n        \"Float\": '\"GPDouble\"',\n        \"String\": '\"GPString\"',\n        \"StringOrNumber\": '[\"GPString\", \"GPDouble\"]',\n        \"Directory\": '\"DEFolder\"',\n        \"Raster\": '\"DERasterDataset\"',\n        \"Csv\": '\"DEFile\"',\n        \"Text\": '\"DEFile\"',\n        \"Html\": '\"DEFile\"',\n        \"Lidar\": '\"DEFile\"',\n        \"Vector\": '\"DEShapefile\"',\n        \"RasterAndVector\": '[\"DERasterDataset\", \"DEShapefile\"]',\n        \"ExistingFileOrFloat\": '[\"DERasterDataset\", \"GPDouble\"]',\n        \"ExistingFile\": '[\"DERasterDataset\"]',\n    }\n\n    vector_filters = {\n        \"Point\": '[\"Point\"]',\n        \"Points\": '[\"Point\"]',\n        \"Line\": '[\"Polyline\"]',\n        \"Lines\": '[\"Polyline\"]',\n        \"Polygon\": '[\"Polygon\"]',\n        \"Polygons\": '[\"Polygon\"]',\n        \"LineOrPolygon\": '[\"Polyline\", \"Polygon\"]',\n        \"Any\": \"[]\",\n    }\n\n    if type(param) is str:\n        data_type = data_types[param]\n\n    else:\n        for item in param:\n            if item == \"FileList\":\n                multi_value = True\n            elif item == \"OptionList\":\n                filter_type = '\"ValueList\"'\n                data_filter = param[item]\n\n            if param[item] == \"Csv\":\n                data_filter = '[\"csv\"]'\n            elif param[item] == \"Lidar\":\n                data_filter = '[\"las\", \"zip\"]'\n            elif param[item] == \"Html\":\n                data_filter = '[\"html\"]'\n\n            if type(param[item]) is str:\n                data_type = data_types[param[item]]\n            elif type(param[item]) is dict:\n                sub_item = param[item]\n                for sub_sub_item in sub_item:\n                    data_type = data_types[sub_sub_item]\n                    if data_type == '\"DEShapefile\"':\n                        data_filter = vector_filters[sub_item[sub_sub_item]]\n            elif item == \"VectorAttributeField\":\n                data_type = '\"Field\"'\n                dependency_field = param[item][1].replace(\"--\", \"\")\n            else:\n                data_type = '\"GPString\"'\n\n            if param == {\"ExistingFileOrFloat\": \"Raster\"}:\n                data_type = '[\"DERasterDataset\", \"GPDouble\"]'\n\n    ret = {}\n    ret[\"data_type\"] = data_type\n    ret[\"data_filter\"] = data_filter\n    ret[\"filter_type\"] = filter_type\n    ret[\"multi_value\"] = multi_value\n    ret[\"dependency_field\"] = dependency_field\n\n    return ret\n\n\ndef get_github_url(tool_name, category):\n    \"\"\"\n    Generate source code link on Github\n    \"\"\"\n    # prefix = \"https://github.com/jblindsay/whitebox-tools/blob/master/src/tools\"\n    url = wbt.view_code(tool_name).strip()\n    # url = \"{}/{}/{}.rs\".format(prefix, category, tool_name)\n    return url\n\n\ndef get_github_tag(tool_name, category):\n    \"\"\"\n    Get GitHub HTML tag\n    \"\"\"\n    # prefix = \"https://github.com/jblindsay/whitebox-tools/blob/master/src/tools\"\n    # url = \"{}/{}/{}.rs\".format(prefix, category, tool_name)\n    url = wbt.view_code(tool_name).strip()\n    # print(tool_name)\n    # if tool_name == \"split_vector_lines\":\n    #     print(url)\n    if \"RUST_BACKTRACE\" in url:\n        url = \"https://github.com/jblindsay/whitebox-tools/tree/master/whitebox-tools-app/src/tools\"\n    html_tag = \"<a href='{}' target='_blank'>GitHub</a>\".format(url)\n    return html_tag\n\n\ndef get_book_url(tool_name, category):\n    \"\"\"\n    Get link to WhiteboxTools User Manual\n    \"\"\"\n    prefix = \"https://www.whiteboxgeo.com/manual/wbt_book/available_tools\"\n    url = \"{}/{}.html#{}\".format(prefix, category, tool_name)\n    return url\n\n\ndef get_book_tag(tool_name, category):\n    \"\"\"\n    Get User Manual HTML tag\n    \"\"\"\n    prefix = \"https://www.whiteboxgeo.com/manual/wbt_book/available_tools\"\n    url = \"{}/{}.html#{}\".format(prefix, category, tool_name)\n    html_tag = \"<a href='{}' target='_blank'>WhiteboxTools User Manual</a>\".format(\n        url)\n    return html_tag\n\n\ndir_path = os.path.dirname(os.path.realpath(__file__))\nwbt_dir = os.path.dirname(dir_path)\nroot_dir = os.path.dirname(wbt_dir)\nwbt_win_zip = os.path.join(root_dir, \"WhiteboxTools_win_amd64.zip\")\n\n# wbt_py = os.path.join(dir_path, \"whitebox_tools.py\")\nwbt_py = os.path.join(wbt_dir, \"whitebox_tools.py\")\n\nfile_header_py = os.path.join(dir_path, \"file_header.py\")\nfile_toolbox_py = os.path.join(dir_path, \"file_toolbox.py\")\nfile_tool_py = os.path.join(dir_path, \"file_tool.py\")\nfile_about_py = os.path.join(dir_path, \"file_about.py\")\n\nfile_wbt_py = os.path.join(dir_path, \"WhiteboxTools.py\")\nfile_wbt_pyt = os.path.join(\n    os.path.dirname(os.path.dirname(dir_path)), \"WhiteboxTools.pyt\"\n)\n\nif not os.path.exists(wbt_win_zip):\n    print(\"Downloading WhiteboxTools binary ...\")\n    url = \"https://www.whiteboxgeo.com/WBT_Windows/WhiteboxTools_win_amd64.zip\"\n    urllib.request.urlretrieve(url, wbt_win_zip)  # Download WhiteboxTools\nelse:\n    print(\"WhiteboxTools binary already exists.\")\n\nprint(\"Decompressing WhiteboxTools_win_amd64.zip ...\")\nwith ZipFile(wbt_win_zip, \"r\") as zipObj:\n    # Extract all the contents of zip file to the root directory\n    zipObj.extractall(root_dir)\n\nMACOSX = os.path.join(root_dir, \"__MACOSX\")\nif os.path.exists(MACOSX):\n    shutil.rmtree(MACOSX)\n\n\ntools_dict = get_wbt_dict()\ntool_labels = [tools_dict[tool][\"label\"] for tool in tools_dict.keys()]\n\nwrite_header(file_header_py, tool_labels)\n\nf_wbt = open(file_wbt_py, \"w\")\n\n# write toolbox header\nwith open(file_header_py) as f:\n    lines = f.readlines()\n    f_wbt.writelines(lines)\n\n# write toolbox class\nwith open(file_toolbox_py) as f:\n    lines = f.readlines()\n    f_wbt.writelines(lines)\n\n# write tool class\nfor tool_name in tools_dict.keys():\n    f_wbt.write(\"        tools.append({})\\n\".format(tool_name))\nf_wbt.write(\"\\n        self.tools = tools\\n\\n\\n\")\n\nwith open(file_about_py) as f:\n    lines = f.readlines()\n    f_wbt.writelines(lines)\n\nfor tool_name in tools_dict:\n    print(tool_name)\n    lines = generate_tool_template(tools_dict[tool_name])\n    f_wbt.writelines(lines)\n\nf_wbt.close()\n\n# copy WhiteboxTools.py to WhiteboxTool.pyt (final ArcGIS Python Toolbox)\nif os.path.exists(file_wbt_pyt):\n    os.remove(file_wbt_pyt)\n    shutil.copyfile(file_wbt_py, file_wbt_pyt)\n\noutlines = []\nwith open(wbt_py) as f:\n    lines = f.readlines()\n    for line in lines:\n        if line.strip() == \"import urllib.request\":\n            line = \"\"\n        if line.strip() == \"from subprocess import CalledProcessError, Popen, PIPE, STDOUT\":\n            line = \"\"\"\nfrom subprocess import CalledProcessError, Popen, PIPE, STDOUT\nif sys.version_info.major == 2:\n    import urllib2 as urlopen\nelse:\n    import urllib.request as urlopen\n            \"\"\"\n        if 'f\"={toolname}\"' in line:\n            line = '                args.append(\"={}\".format(toolname))'\n        if line.strip() == 'args2.append(f\"--max_procs={val}\")':\n            line = '            args2.append(\"--max_procs={}\".format(val))'\n        if 'f\"Warning: Unrecognized extension ext_name {ext_name}' in line:\n            line = '                    print(\"Warning: Unrecognized extension ext_name {}. Installing the GTE instead...\".format(ext_name))\\n'\n        if line.strip() == \"for entry in os.scandir(f'./{unzipped_dir_name}'):\":\n            line = \"            for entry in os.scandir('./{}'.format(unzipped_dir_name)):\\n\"\n        if line.strip() == \"new_path = entry.path.replace(f'{unzipped_dir_name}', 'plugins')\":\n            line = \"                new_path = entry.path.replace('{}'.format(unzipped_dir_name), 'plugins')\\n\"\n        if line.strip() == \"if os.path.exists(f'./{unzipped_dir_name}'):\":\n            line = \"            if os.path.exists('./{}'.format(unzipped_dir_name)):\\n\"\n        if line.strip() == \"shutil.rmtree(f'./{unzipped_dir_name}')\":\n            line = \"                shutil.rmtree('./{}'.format(unzipped_dir_name))\\n\"\n        if \"urllib.request\" in line and \"import\" not in line:\n            line = line.replace(\"urllib.request\", \"urlopen\")\n\n        outlines.append(line)\n\nwith open(wbt_py, \"w\") as f:\n    f.writelines(outlines)\n"
  },
  {
    "path": "WBT/PRE/file_about.py",
    "content": "class Help(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"Help\"\n        self.description = \"Help description for WhiteboxTools\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        params = None\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        messages.addMessage(wbt.help())\n        return\n\n\nclass License(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"License\"\n        self.description = \"License information for WhiteboxTools.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        params = None\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        messages.addMessage(wbt.license())\n        return\n\n\nclass Version(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"Version\"\n        self.description = \"Version information for WhiteboxTools.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        params = None\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        messages.addMessage(wbt.version())\n        return\n\n\nclass ListTools(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"List Tools\"\n        self.description = \"All available tools in WhiteboxTools.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n\n        # First parameter\n        param0 = arcpy.Parameter(\n            displayName=\"Keywords\",\n            name=\"keywords\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        # param0.multiValue = True\n        param0.value = \"lidar\"\n        params = [param0]\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        param0 = parameters[0].valueAsText\n\n        if param0 is None:\n            tools = wbt.list_tools()\n        else:\n            tools = wbt.list_tools([param0])\n            \n        for index, tool in enumerate(sorted(tools)):\n            messages.addMessage(\"{}. {}: {}\".format(index + 1, tool, tools[tool]))\n        return\n\n\nclass ToolHelp(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"Tool Help\"\n        self.description = \"Help description for a specific tool.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        tool_name = arcpy.Parameter(\n            displayName=\"Select a tool\",\n            name=\"tool_name\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        tool_name.value = \"Lidar Info\"\n        tool_name.filter.type = \"ValueList\"\n        tool_name.filter.list = tool_labels\n\n        params = [tool_name]\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        param0 = parameters[0].valueAsText\n        tool_name = param0.replace(\" \", \"\").strip()\n        messages.addMessage(wbt.tool_help(tool_name))\n        return\n\n\nclass ToolParameters(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"Tool Parameters\"\n        self.description = \"Tool parameter descriptions for a specific tool.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        tool_name = arcpy.Parameter(\n            displayName=\"Select a tool\",\n            name=\"tool_name\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        tool_name.value = \"Lidar Info\"\n        tool_name.filter.type = \"ValueList\"\n        tool_name.filter.list = tool_labels\n\n        params = [tool_name]\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        param0 = parameters[0].valueAsText\n        tool_name = param0.replace(\" \", \"\").strip()\n        messages.addMessage(wbt.tool_parameters(tool_name))\n        return\n\n\nclass ViewCode(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"View Code\"\n        self.description = \"Source code for a specific tool.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        tool_name = arcpy.Parameter(\n            displayName=\"Select a tool\",\n            name=\"tool_name\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        tool_name.value = \"Lidar Info\"\n        tool_name.filter.type = \"ValueList\"\n        tool_name.filter.list = tool_labels\n\n        params = [tool_name]\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        param0 = parameters[0].valueAsText\n        tool_name = param0.replace(\" \", \"\").strip()        \n        messages.addMessage(\"Opening default browser...\")\n        webbrowser.get('windows-default').open(wbt.view_code(tool_name))\n        messages.addMessage(wbt.view_code(tool_name))\n        return\n\n\nclass RunTool(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"Run Tool\"\n        self.description = \"Runs a tool and specifies tool arguments.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        tool_name = arcpy.Parameter(\n            displayName=\"Select a tool\",\n            name=\"tool_name\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        tool_name.value = \"Breach Depressions\"\n        tool_name.filter.type = \"ValueList\"\n        tool_name.filter.list = tool_labels\n\n        args = arcpy.Parameter(\n            displayName=\"Arguments\",\n            name=\"agrs\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        args.value = '--dem=\"/path/to/DEM.tif\"  --output=\"/path/to/output.tif\"'\n\n        params = [tool_name, args]\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        param0 = parameters[0].valueAsText\n        args = parameters[1].valueAsText\n        tool_name = param0.replace(\" \", \"\").strip()\n        dir_path = os.path.dirname(os.path.realpath(__file__))    \n        exe_path = os.path.join(dir_path, \"WBT/whitebox_tools.exe\")\n        cmd = '{} --run={} {}'.format(exe_path, tool_name, args)\n        if \"-v\" not in cmd:\n            cmd = cmd + ' -v'  \n        messages.addMessage(cmd)  \n        messages.addMessage(os.popen(cmd).read().rstrip())\n        return\n\n\n"
  },
  {
    "path": "WBT/PRE/file_header.py",
    "content": "import arcpy\nimport os\nimport webbrowser\nfrom WBT.whitebox_tools import WhiteboxTools\nif sys.version_info < (3, 0):\n    from StringIO import StringIO\nelse:\n    from io import StringIO\n\nwbt = WhiteboxTools()\ntool_labels = []\n\ntool_labels.append(\"Absolute Value\")\ntool_labels.append(\"Accumulation Curvature\")\ntool_labels.append(\"Adaptive Filter\")\ntool_labels.append(\"Add\")\ntool_labels.append(\"Add Point Coordinates To Table\")\ntool_labels.append(\"Aggregate Raster\")\ntool_labels.append(\"And\")\ntool_labels.append(\"Anova\")\ntool_labels.append(\"Arc Cos\")\ntool_labels.append(\"Arc Sin\")\ntool_labels.append(\"Arc Tan\")\ntool_labels.append(\"Arcosh\")\ntool_labels.append(\"Arsinh\")\ntool_labels.append(\"Artanh\")\ntool_labels.append(\"Ascii To Las\")\ntool_labels.append(\"Aspect\")\ntool_labels.append(\"Assess Route\")\ntool_labels.append(\"Atan2\")\ntool_labels.append(\"Attribute Correlation\")\ntool_labels.append(\"Attribute Correlation Neighbourhood Analysis\")\ntool_labels.append(\"Attribute Histogram\")\ntool_labels.append(\"Attribute Scattergram\")\ntool_labels.append(\"Average Flowpath Slope\")\ntool_labels.append(\"Average Normal Vector Angular Deviation\")\ntool_labels.append(\"Average Overlay\")\ntool_labels.append(\"Average Upslope Flowpath Length\")\ntool_labels.append(\"Balance Contrast Enhancement\")\ntool_labels.append(\"Basins\")\ntool_labels.append(\"Bilateral Filter\")\ntool_labels.append(\"Block Maximum Gridding\")\ntool_labels.append(\"Block Minimum Gridding\")\ntool_labels.append(\"Boundary Shape Complexity\")\ntool_labels.append(\"Breach Depressions\")\ntool_labels.append(\"Breach Depressions Least Cost\")\ntool_labels.append(\"Breach Single Cell Pits\")\ntool_labels.append(\"Breakline Mapping\")\ntool_labels.append(\"Buffer Raster\")\ntool_labels.append(\"Burn Streams At Roads\")\ntool_labels.append(\"Canny Edge Detection\")\ntool_labels.append(\"Ceil\")\ntool_labels.append(\"Centroid\")\ntool_labels.append(\"Centroid Vector\")\ntool_labels.append(\"Change Vector Analysis\")\ntool_labels.append(\"Circular Variance Of Aspect\")\ntool_labels.append(\"Classify Buildings In Lidar\")\ntool_labels.append(\"Classify Lidar\")\ntool_labels.append(\"Classify Overlap Points\")\ntool_labels.append(\"Clean Vector\")\ntool_labels.append(\"Clip\")\ntool_labels.append(\"Clip Lidar To Polygon\")\ntool_labels.append(\"Clip Raster To Polygon\")\ntool_labels.append(\"Closing\")\ntool_labels.append(\"Clump\")\ntool_labels.append(\"Colourize Based On Class\")\ntool_labels.append(\"Colourize Based On Point Returns\")\ntool_labels.append(\"Compactness Ratio\")\ntool_labels.append(\"Conditional Evaluation\")\ntool_labels.append(\"Conditioned Latin Hypercube\")\ntool_labels.append(\"Conservative Smoothing Filter\")\ntool_labels.append(\"Construct Vector Tin\")\ntool_labels.append(\"Contours From Points\")\ntool_labels.append(\"Contours From Raster\")\ntool_labels.append(\"Convert Nodata To Zero\")\ntool_labels.append(\"Convert Raster Format\")\ntool_labels.append(\"Corner Detection\")\ntool_labels.append(\"Correct Vignetting\")\ntool_labels.append(\"Cos\")\ntool_labels.append(\"Cosh\")\ntool_labels.append(\"Cost Allocation\")\ntool_labels.append(\"Cost Distance\")\ntool_labels.append(\"Cost Pathway\")\ntool_labels.append(\"Count If\")\ntool_labels.append(\"Create Colour Composite\")\ntool_labels.append(\"Create Hexagonal Vector Grid\")\ntool_labels.append(\"Create Plane\")\ntool_labels.append(\"Create Rectangular Vector Grid\")\ntool_labels.append(\"Crispness Index\")\ntool_labels.append(\"Cross Tabulation\")\ntool_labels.append(\"Csv Points To Vector\")\ntool_labels.append(\"Cumulative Distribution\")\ntool_labels.append(\"Curvedness\")\ntool_labels.append(\"D Inf Flow Accumulation\")\ntool_labels.append(\"D Inf Mass Flux\")\ntool_labels.append(\"D Inf Pointer\")\ntool_labels.append(\"D8 Flow Accumulation\")\ntool_labels.append(\"D8 Mass Flux\")\ntool_labels.append(\"D8 Pointer\")\ntool_labels.append(\"Dbscan\")\ntool_labels.append(\"Decrement\")\ntool_labels.append(\"Dem Void Filling\")\ntool_labels.append(\"Depth In Sink\")\ntool_labels.append(\"Depth To Water\")\ntool_labels.append(\"Dev From Mean Elev\")\ntool_labels.append(\"Diff From Mean Elev\")\ntool_labels.append(\"Diff Of Gaussian Filter\")\ntool_labels.append(\"Difference\")\ntool_labels.append(\"Difference Curvature\")\ntool_labels.append(\"Direct Decorrelation Stretch\")\ntool_labels.append(\"Directional Relief\")\ntool_labels.append(\"Dissolve\")\ntool_labels.append(\"Distance To Outlet\")\ntool_labels.append(\"Diversity Filter\")\ntool_labels.append(\"Divide\")\ntool_labels.append(\"Downslope Distance To Stream\")\ntool_labels.append(\"Downslope Flowpath Length\")\ntool_labels.append(\"Downslope Index\")\ntool_labels.append(\"Edge Contamination\")\ntool_labels.append(\"Edge Density\")\ntool_labels.append(\"Edge Preserving Mean Filter\")\ntool_labels.append(\"Edge Proportion\")\ntool_labels.append(\"Elev Above Pit\")\ntool_labels.append(\"Elev Percentile\")\ntool_labels.append(\"Elev Relative To Min Max\")\ntool_labels.append(\"Elev Relative To Watershed Min Max\")\ntool_labels.append(\"Elevation Above Stream\")\ntool_labels.append(\"Elevation Above Stream Euclidean\")\ntool_labels.append(\"Eliminate Coincident Points\")\ntool_labels.append(\"Elongation Ratio\")\ntool_labels.append(\"Embankment Mapping\")\ntool_labels.append(\"Emboss Filter\")\ntool_labels.append(\"Equal To\")\ntool_labels.append(\"Erase\")\ntool_labels.append(\"Erase Polygon From Lidar\")\ntool_labels.append(\"Erase Polygon From Raster\")\ntool_labels.append(\"Euclidean Allocation\")\ntool_labels.append(\"Euclidean Distance\")\ntool_labels.append(\"Evaluate Training Sites\")\ntool_labels.append(\"Exp\")\ntool_labels.append(\"Exp2\")\ntool_labels.append(\"Export Table To Csv\")\ntool_labels.append(\"Exposure Towards Wind Flux\")\ntool_labels.append(\"Extend Vector Lines\")\ntool_labels.append(\"Extract Nodes\")\ntool_labels.append(\"Extract Raster Values At Points\")\ntool_labels.append(\"Extract Streams\")\ntool_labels.append(\"Extract Valleys\")\ntool_labels.append(\"Farthest Channel Head\")\ntool_labels.append(\"Fast Almost Gaussian Filter\")\ntool_labels.append(\"Fd8 Flow Accumulation\")\ntool_labels.append(\"Fd8 Pointer\")\ntool_labels.append(\"Feature Preserving Smoothing\")\ntool_labels.append(\"Fetch Analysis\")\ntool_labels.append(\"Fill Burn\")\ntool_labels.append(\"Fill Depressions\")\ntool_labels.append(\"Fill Depressions Planchon And Darboux\")\ntool_labels.append(\"Fill Depressions Wang And Liu\")\ntool_labels.append(\"Fill Missing Data\")\ntool_labels.append(\"Fill Single Cell Pits\")\ntool_labels.append(\"Filter Lidar\")\ntool_labels.append(\"Filter Lidar Classes\")\ntool_labels.append(\"Filter Lidar Scan Angles\")\ntool_labels.append(\"Filter Raster Features By Area\")\ntool_labels.append(\"Find Flightline Edge Points\")\ntool_labels.append(\"Find Lowest Or Highest Points\")\ntool_labels.append(\"Find Main Stem\")\ntool_labels.append(\"Find No Flow Cells\")\ntool_labels.append(\"Find Parallel Flow\")\ntool_labels.append(\"Find Patch Or Class Edge Cells\")\ntool_labels.append(\"Find Ridges\")\ntool_labels.append(\"Fix Dangling Arcs\")\ntool_labels.append(\"Flatten Lakes\")\ntool_labels.append(\"Flightline Overlap\")\ntool_labels.append(\"Flip Image\")\ntool_labels.append(\"Flood Order\")\ntool_labels.append(\"Floor\")\ntool_labels.append(\"Flow Accumulation Full Workflow\")\ntool_labels.append(\"Flow Length Diff\")\ntool_labels.append(\"Gamma Correction\")\ntool_labels.append(\"Gaussian Contrast Stretch\")\ntool_labels.append(\"Gaussian Curvature\")\ntool_labels.append(\"Gaussian Filter\")\ntool_labels.append(\"Gaussian Scale Space\")\ntool_labels.append(\"Generalize Classified Raster\")\ntool_labels.append(\"Generalize With Similarity\")\ntool_labels.append(\"Generating Function\")\ntool_labels.append(\"Geomorphons\")\ntool_labels.append(\"Greater Than\")\ntool_labels.append(\"Hack Stream Order\")\ntool_labels.append(\"Heat Map\")\ntool_labels.append(\"Height Above Ground\")\ntool_labels.append(\"High Pass Bilateral Filter\")\ntool_labels.append(\"High Pass Filter\")\ntool_labels.append(\"High Pass Median Filter\")\ntool_labels.append(\"Highest Position\")\ntool_labels.append(\"Hillshade\")\ntool_labels.append(\"Hillslopes\")\ntool_labels.append(\"Histogram Equalization\")\ntool_labels.append(\"Histogram Matching\")\ntool_labels.append(\"Histogram Matching Two Images\")\ntool_labels.append(\"Hole Proportion\")\ntool_labels.append(\"Horizon Angle\")\ntool_labels.append(\"Horizontal Excess Curvature\")\ntool_labels.append(\"Horton Stream Order\")\ntool_labels.append(\"Hydrologic Connectivity\")\ntool_labels.append(\"Hypsometric Analysis\")\ntool_labels.append(\"Hypsometrically Tinted Hillshade\")\ntool_labels.append(\"Idw Interpolation\")\ntool_labels.append(\"Ihs To Rgb\")\ntool_labels.append(\"Image Autocorrelation\")\ntool_labels.append(\"Image Correlation\")\ntool_labels.append(\"Image Correlation Neighbourhood Analysis\")\ntool_labels.append(\"Image Regression\")\ntool_labels.append(\"Image Segmentation\")\ntool_labels.append(\"Image Slider\")\ntool_labels.append(\"Image Stack Profile\")\ntool_labels.append(\"Impoundment Size Index\")\ntool_labels.append(\"In Place Add\")\ntool_labels.append(\"In Place Divide\")\ntool_labels.append(\"In Place Multiply\")\ntool_labels.append(\"In Place Subtract\")\ntool_labels.append(\"Increment\")\ntool_labels.append(\"Individual Tree Detection\")\ntool_labels.append(\"Insert Dams\")\ntool_labels.append(\"Install Wb Extension\")\ntool_labels.append(\"Integer Division\")\ntool_labels.append(\"Integral Image\")\ntool_labels.append(\"Intersect\")\ntool_labels.append(\"Inverse Pca\")\ntool_labels.append(\"Is No Data\")\ntool_labels.append(\"Isobasins\")\ntool_labels.append(\"Jenson Snap Pour Points\")\ntool_labels.append(\"Join Tables\")\ntool_labels.append(\"K Means Clustering\")\ntool_labels.append(\"K Nearest Mean Filter\")\ntool_labels.append(\"Kappa Index\")\ntool_labels.append(\"Knn Classification\")\ntool_labels.append(\"Knn Regression\")\ntool_labels.append(\"Ks Test For Normality\")\ntool_labels.append(\"Laplacian Filter\")\ntool_labels.append(\"Laplacian Of Gaussian Filter\")\ntool_labels.append(\"Las To Ascii\")\ntool_labels.append(\"Las To Laz\")\ntool_labels.append(\"Las To Multipoint Shapefile\")\ntool_labels.append(\"Las To Shapefile\")\ntool_labels.append(\"Las To Zlidar\")\ntool_labels.append(\"Launch Wb Runner\")\ntool_labels.append(\"Layer Footprint\")\ntool_labels.append(\"Laz To Las\")\ntool_labels.append(\"Lee Sigma Filter\")\ntool_labels.append(\"Length Of Upstream Channels\")\ntool_labels.append(\"Less Than\")\ntool_labels.append(\"Lidar Block Maximum\")\ntool_labels.append(\"Lidar Block Minimum\")\ntool_labels.append(\"Lidar Classify Subset\")\ntool_labels.append(\"Lidar Colourize\")\ntool_labels.append(\"Lidar Contour\")\ntool_labels.append(\"Lidar Digital Surface Model\")\ntool_labels.append(\"Lidar Eigenvalue Features\")\ntool_labels.append(\"Lidar Elevation Slice\")\ntool_labels.append(\"Lidar Ground Point Filter\")\ntool_labels.append(\"Lidar Hex Binning\")\ntool_labels.append(\"Lidar Hillshade\")\ntool_labels.append(\"Lidar Histogram\")\ntool_labels.append(\"Lidar Idw Interpolation\")\ntool_labels.append(\"Lidar Info\")\ntool_labels.append(\"Lidar Join\")\ntool_labels.append(\"Lidar Kappa Index\")\ntool_labels.append(\"Lidar Nearest Neighbour Gridding\")\ntool_labels.append(\"Lidar Point Density\")\ntool_labels.append(\"Lidar Point Return Analysis\")\ntool_labels.append(\"Lidar Point Stats\")\ntool_labels.append(\"Lidar Ransac Planes\")\ntool_labels.append(\"Lidar Rbf Interpolation\")\ntool_labels.append(\"Lidar Remove Duplicates\")\ntool_labels.append(\"Lidar Remove Outliers\")\ntool_labels.append(\"Lidar Rooftop Analysis\")\ntool_labels.append(\"Lidar Segmentation\")\ntool_labels.append(\"Lidar Segmentation Based Filter\")\ntool_labels.append(\"Lidar Shift\")\ntool_labels.append(\"Lidar Sibson Interpolation\")\ntool_labels.append(\"Lidar Thin\")\ntool_labels.append(\"Lidar Thin High Density\")\ntool_labels.append(\"Lidar Tile\")\ntool_labels.append(\"Lidar Tile Footprint\")\ntool_labels.append(\"Lidar Tin Gridding\")\ntool_labels.append(\"Lidar Tophat Transform\")\ntool_labels.append(\"Line Detection Filter\")\ntool_labels.append(\"Line Intersections\")\ntool_labels.append(\"Line Thinning\")\ntool_labels.append(\"Linearity Index\")\ntool_labels.append(\"Lines To Polygons\")\ntool_labels.append(\"List Unique Values\")\ntool_labels.append(\"List Unique Values Raster\")\ntool_labels.append(\"Ln\")\ntool_labels.append(\"Local Hypsometric Analysis\")\ntool_labels.append(\"Local Quadratic Regression\")\ntool_labels.append(\"Log10\")\ntool_labels.append(\"Log2\")\ntool_labels.append(\"Logistic Regression\")\ntool_labels.append(\"Long Profile\")\ntool_labels.append(\"Long Profile From Points\")\ntool_labels.append(\"Longest Flowpath\")\ntool_labels.append(\"Low Points On Headwater Divides\")\ntool_labels.append(\"Lowest Position\")\ntool_labels.append(\"Majority Filter\")\ntool_labels.append(\"Map Off Terrain Objects\")\ntool_labels.append(\"Max\")\ntool_labels.append(\"Max Absolute Overlay\")\ntool_labels.append(\"Max Anisotropy Dev\")\ntool_labels.append(\"Max Anisotropy Dev Signature\")\ntool_labels.append(\"Max Branch Length\")\ntool_labels.append(\"Max Difference From Mean\")\ntool_labels.append(\"Max Downslope Elev Change\")\ntool_labels.append(\"Max Elev Dev Signature\")\ntool_labels.append(\"Max Elevation Deviation\")\ntool_labels.append(\"Max Overlay\")\ntool_labels.append(\"Max Upslope Elev Change\")\ntool_labels.append(\"Max Upslope Flowpath Length\")\ntool_labels.append(\"Max Upslope Value\")\ntool_labels.append(\"Maximal Curvature\")\ntool_labels.append(\"Maximum Filter\")\ntool_labels.append(\"Md Inf Flow Accumulation\")\ntool_labels.append(\"Mean Curvature\")\ntool_labels.append(\"Mean Filter\")\ntool_labels.append(\"Median Filter\")\ntool_labels.append(\"Medoid\")\ntool_labels.append(\"Merge Line Segments\")\ntool_labels.append(\"Merge Table With Csv\")\ntool_labels.append(\"Merge Vectors\")\ntool_labels.append(\"Min\")\ntool_labels.append(\"Min Absolute Overlay\")\ntool_labels.append(\"Min Dist Classification\")\ntool_labels.append(\"Min Downslope Elev Change\")\ntool_labels.append(\"Min Max Contrast Stretch\")\ntool_labels.append(\"Min Overlay\")\ntool_labels.append(\"Minimal Curvature\")\ntool_labels.append(\"Minimum Bounding Box\")\ntool_labels.append(\"Minimum Bounding Circle\")\ntool_labels.append(\"Minimum Bounding Envelope\")\ntool_labels.append(\"Minimum Convex Hull\")\ntool_labels.append(\"Minimum Filter\")\ntool_labels.append(\"Modified K Means Clustering\")\ntool_labels.append(\"Modify Lidar\")\ntool_labels.append(\"Modify No Data Value\")\ntool_labels.append(\"Modulo\")\ntool_labels.append(\"Mosaic\")\ntool_labels.append(\"Mosaic With Feathering\")\ntool_labels.append(\"Multi Part To Single Part\")\ntool_labels.append(\"Multidirectional Hillshade\")\ntool_labels.append(\"Multiply\")\ntool_labels.append(\"Multiply Overlay\")\ntool_labels.append(\"Multiscale Curvatures\")\ntool_labels.append(\"Multiscale Elevation Percentile\")\ntool_labels.append(\"Multiscale Roughness\")\ntool_labels.append(\"Multiscale Roughness Signature\")\ntool_labels.append(\"Multiscale Std Dev Normals\")\ntool_labels.append(\"Multiscale Std Dev Normals Signature\")\ntool_labels.append(\"Multiscale Topographic Position Image\")\ntool_labels.append(\"Narrowness Index\")\ntool_labels.append(\"Natural Neighbour Interpolation\")\ntool_labels.append(\"Nearest Neighbour Gridding\")\ntool_labels.append(\"Negate\")\ntool_labels.append(\"New Raster From Base\")\ntool_labels.append(\"Normal Vectors\")\ntool_labels.append(\"Normalize Lidar\")\ntool_labels.append(\"Normalized Difference Index\")\ntool_labels.append(\"Not\")\ntool_labels.append(\"Not Equal To\")\ntool_labels.append(\"Num Downslope Neighbours\")\ntool_labels.append(\"Num Inflowing Neighbours\")\ntool_labels.append(\"Num Upslope Neighbours\")\ntool_labels.append(\"Olympic Filter\")\ntool_labels.append(\"Opening\")\ntool_labels.append(\"Openness\")\ntool_labels.append(\"Or\")\ntool_labels.append(\"Paired Sample T Test\")\ntool_labels.append(\"Panchromatic Sharpening\")\ntool_labels.append(\"Parallelepiped Classification\")\ntool_labels.append(\"Patch Orientation\")\ntool_labels.append(\"Pennock Landform Class\")\ntool_labels.append(\"Percent Elev Range\")\ntool_labels.append(\"Percent Equal To\")\ntool_labels.append(\"Percent Greater Than\")\ntool_labels.append(\"Percent Less Than\")\ntool_labels.append(\"Percentage Contrast Stretch\")\ntool_labels.append(\"Percentile Filter\")\ntool_labels.append(\"Perimeter Area Ratio\")\ntool_labels.append(\"Phi Coefficient\")\ntool_labels.append(\"Pick From List\")\ntool_labels.append(\"Piecewise Contrast Stretch\")\ntool_labels.append(\"Plan Curvature\")\ntool_labels.append(\"Polygon Area\")\ntool_labels.append(\"Polygon Long Axis\")\ntool_labels.append(\"Polygon Perimeter\")\ntool_labels.append(\"Polygon Short Axis\")\ntool_labels.append(\"Polygonize\")\ntool_labels.append(\"Polygons To Lines\")\ntool_labels.append(\"Power\")\ntool_labels.append(\"Prewitt Filter\")\ntool_labels.append(\"Principal Component Analysis\")\ntool_labels.append(\"Print Geo Tiff Tags\")\ntool_labels.append(\"Profile\")\ntool_labels.append(\"Profile Curvature\")\ntool_labels.append(\"Qin Flow Accumulation\")\ntool_labels.append(\"Quantiles\")\ntool_labels.append(\"Quinn Flow Accumulation\")\ntool_labels.append(\"Radial Basis Function Interpolation\")\ntool_labels.append(\"Radius Of Gyration\")\ntool_labels.append(\"Raise Walls\")\ntool_labels.append(\"Random Field\")\ntool_labels.append(\"Random Forest Classification\")\ntool_labels.append(\"Random Forest Regression\")\ntool_labels.append(\"Random Sample\")\ntool_labels.append(\"Range Filter\")\ntool_labels.append(\"Raster Area\")\ntool_labels.append(\"Raster Calculator\")\ntool_labels.append(\"Raster Cell Assignment\")\ntool_labels.append(\"Raster Histogram\")\ntool_labels.append(\"Raster Perimeter\")\ntool_labels.append(\"Raster Streams To Vector\")\ntool_labels.append(\"Raster Summary Stats\")\ntool_labels.append(\"Raster To Vector Lines\")\ntool_labels.append(\"Raster To Vector Points\")\ntool_labels.append(\"Raster To Vector Polygons\")\ntool_labels.append(\"Rasterize Streams\")\ntool_labels.append(\"Reciprocal\")\ntool_labels.append(\"Reclass\")\ntool_labels.append(\"Reclass Equal Interval\")\ntool_labels.append(\"Reclass From File\")\ntool_labels.append(\"Reconcile Multiple Headers\")\ntool_labels.append(\"Recover Flightline Info\")\ntool_labels.append(\"Recreate Pass Lines\")\ntool_labels.append(\"Reinitialize Attribute Table\")\ntool_labels.append(\"Related Circumscribing Circle\")\ntool_labels.append(\"Relative Aspect\")\ntool_labels.append(\"Relative Topographic Position\")\ntool_labels.append(\"Remove Field Edge Points\")\ntool_labels.append(\"Remove Off Terrain Objects\")\ntool_labels.append(\"Remove Polygon Holes\")\ntool_labels.append(\"Remove Raster Polygon Holes\")\ntool_labels.append(\"Remove Short Streams\")\ntool_labels.append(\"Remove Spurs\")\ntool_labels.append(\"Repair Stream Vector Topology\")\ntool_labels.append(\"Resample\")\ntool_labels.append(\"Rescale Value Range\")\ntool_labels.append(\"Rgb To Ihs\")\ntool_labels.append(\"Rho8 Flow Accumulation\")\ntool_labels.append(\"Rho8 Pointer\")\ntool_labels.append(\"Ring Curvature\")\ntool_labels.append(\"River Centerlines\")\ntool_labels.append(\"Roberts Cross Filter\")\ntool_labels.append(\"Root Mean Square Error\")\ntool_labels.append(\"Rotor\")\ntool_labels.append(\"Round\")\ntool_labels.append(\"Ruggedness Index\")\ntool_labels.append(\"Scharr Filter\")\ntool_labels.append(\"Sediment Transport Index\")\ntool_labels.append(\"Select Tiles By Polygon\")\ntool_labels.append(\"Set Nodata Value\")\ntool_labels.append(\"Shadow Animation\")\ntool_labels.append(\"Shadow Image\")\ntool_labels.append(\"Shape Complexity Index\")\ntool_labels.append(\"Shape Complexity Index Raster\")\ntool_labels.append(\"Shape Index\")\ntool_labels.append(\"Shreve Stream Magnitude\")\ntool_labels.append(\"Sigmoidal Contrast Stretch\")\ntool_labels.append(\"Sin\")\ntool_labels.append(\"Single Part To Multi Part\")\ntool_labels.append(\"Sinh\")\ntool_labels.append(\"Sink\")\ntool_labels.append(\"Slope\")\ntool_labels.append(\"Slope Vs Aspect Plot\")\ntool_labels.append(\"Slope Vs Elevation Plot\")\ntool_labels.append(\"Smooth Vectors\")\ntool_labels.append(\"Smooth Vegetation Residual\")\ntool_labels.append(\"Snap Pour Points\")\ntool_labels.append(\"Sobel Filter\")\ntool_labels.append(\"Sort Lidar\")\ntool_labels.append(\"Spherical Std Dev Of Normals\")\ntool_labels.append(\"Split Colour Composite\")\ntool_labels.append(\"Split Lidar\")\ntool_labels.append(\"Split Vector Lines\")\ntool_labels.append(\"Split With Lines\")\ntool_labels.append(\"Square\")\ntool_labels.append(\"Square Root\")\ntool_labels.append(\"Standard Deviation Contrast Stretch\")\ntool_labels.append(\"Standard Deviation Filter\")\ntool_labels.append(\"Standard Deviation Of Slope\")\ntool_labels.append(\"Stochastic Depression Analysis\")\ntool_labels.append(\"Strahler Order Basins\")\ntool_labels.append(\"Strahler Stream Order\")\ntool_labels.append(\"Stream Link Class\")\ntool_labels.append(\"Stream Link Identifier\")\ntool_labels.append(\"Stream Link Length\")\ntool_labels.append(\"Stream Link Slope\")\ntool_labels.append(\"Stream Power Index\")\ntool_labels.append(\"Stream Slope Continuous\")\ntool_labels.append(\"Subbasins\")\ntool_labels.append(\"Subtract\")\ntool_labels.append(\"Sum Overlay\")\ntool_labels.append(\"Surface Area Ratio\")\ntool_labels.append(\"Svm Classification\")\ntool_labels.append(\"Svm Regression\")\ntool_labels.append(\"Symmetrical Difference\")\ntool_labels.append(\"Tan\")\ntool_labels.append(\"Tangential Curvature\")\ntool_labels.append(\"Tanh\")\ntool_labels.append(\"Thicken Raster Line\")\ntool_labels.append(\"Time In Daylight\")\ntool_labels.append(\"Tin Gridding\")\ntool_labels.append(\"To Degrees\")\ntool_labels.append(\"To Radians\")\ntool_labels.append(\"Tophat Transform\")\ntool_labels.append(\"Topo Render\")\ntool_labels.append(\"Topographic Position Animation\")\ntool_labels.append(\"Topological Stream Order\")\ntool_labels.append(\"Total Curvature\")\ntool_labels.append(\"Total Filter\")\ntool_labels.append(\"Trace Downslope Flowpaths\")\ntool_labels.append(\"Travelling Salesman Problem\")\ntool_labels.append(\"Trend Surface\")\ntool_labels.append(\"Trend Surface Vector Points\")\ntool_labels.append(\"Tributary Identifier\")\ntool_labels.append(\"Truncate\")\ntool_labels.append(\"Turning Bands Simulation\")\ntool_labels.append(\"Two Sample Ks Test\")\ntool_labels.append(\"Union\")\ntool_labels.append(\"Unnest Basins\")\ntool_labels.append(\"Unsharp Masking\")\ntool_labels.append(\"Unsphericity\")\ntool_labels.append(\"Update Nodata Cells\")\ntool_labels.append(\"Upslope Depression Storage\")\ntool_labels.append(\"User Defined Weights Filter\")\ntool_labels.append(\"Vector Hex Binning\")\ntool_labels.append(\"Vector Lines To Raster\")\ntool_labels.append(\"Vector Points To Raster\")\ntool_labels.append(\"Vector Polygons To Raster\")\ntool_labels.append(\"Vector Stream Network Analysis\")\ntool_labels.append(\"Vertical Excess Curvature\")\ntool_labels.append(\"Viewshed\")\ntool_labels.append(\"Visibility Index\")\ntool_labels.append(\"Voronoi Diagram\")\ntool_labels.append(\"Watershed\")\ntool_labels.append(\"Weighted Overlay\")\ntool_labels.append(\"Weighted Sum\")\ntool_labels.append(\"Wetness Index\")\ntool_labels.append(\"Wilcoxon Signed Rank Test\")\ntool_labels.append(\"Write Function Memory Insertion\")\ntool_labels.append(\"Xor\")\ntool_labels.append(\"Yield Filter\")\ntool_labels.append(\"Yield Map\")\ntool_labels.append(\"Yield Normalization\")\ntool_labels.append(\"Z Scores\")\ntool_labels.append(\"Zlidar To Las\")\ntool_labels.append(\"Zonal Statistics\")\n\n\n"
  },
  {
    "path": "WBT/PRE/file_tool.py",
    "content": "class Tool(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"Tool\"\n        self.description = \"\"\n        self.category = \"\"\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        params = None\n        return params\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        return\n\n\n        "
  },
  {
    "path": "WBT/PRE/file_toolbox.py",
    "content": "class Toolbox(object):\n    def __init__(self):\n        \"\"\"Define the toolbox (the name of the toolbox is the name of the .pyt file).\"\"\"\n        self.label = \"WhiteboxTools Toolbox\"\n        self.alias = \"WBT\"\n\n        # List of tool classes associated with this toolbox\n        tools = []        \n        tools.append(Help)\n        tools.append(License)\n        tools.append(Version)\n        tools.append(ListTools)\n        tools.append(ToolHelp)\n        tools.append(ToolParameters)\n        tools.append(ViewCode)\n        tools.append(RunTool)\n\n"
  },
  {
    "path": "WBT/PRE/testing.py",
    "content": "import whitebox\nimport ast\nimport json\nimport os\nimport sys\n\nwbt = whitebox.WhiteboxTools()\n# wbt.set_verbose_mode(True)\n# print(wbt.version())\n# print(wbt.help())\n\n\n# tools = wbt.list_tools(['dem'])\n\n\n# for index, tool in enumerate(tools):\n#     print(\"{}. {}: {}\".format(index, tool, tools[tool]))\n\n# def get_tool_params(tool_name):\n\n#     out_str = wbt.tool_parameters(tool_name)\n#     start_index = out_str.index('[') + 1\n#     end_index = len(out_str.strip()) - 2\n#     params = out_str[start_index : end_index]\n#     print(params)\n\n#     sub_params = params.split('{\"name\"')\n#     param_list = []\n\n#     for param in sub_params:\n#         param = param.strip()\n#         if len(param) > 0:\n#             item = '\"name\"' + param\n#             item = item[ : item.rfind(\"}\")].strip()\n#             param_list.append(item)\n\n#     params_dict = {}\n#     for item in param_list:\n#         print(\"{}\\n\".format(item))\n#         param_dict = {}\n#         index_name = item.find(\"name\")\n#         index_flags = item.find(\"flags\")\n#         index_description = item.find(\"description\")\n#         index_parameter_type = item.find(\"parameter_type\")\n#         index_default_value = item.find(\"default_value\")\n#         index_optional = item.find(\"optional\")\n\n#         name = item[index_name - 1 : index_flags - 2].replace('\"name\":', '')\n#         name = name.replace('\"', '')\n#         param_dict['name'] = name\n\n#         flags = item[index_flags - 1 : index_description -2].replace('\"flags\":', '')\n#         if \"--\" in flags:\n#             flags = flags.split('--')[1][: -2]\n#         else:\n#             flags = flags.split('-')[1][: -2]\n#         param_dict['flags'] = flags\n\n#         desc = item[index_description - 1 : index_parameter_type - 2].replace('\"description\":', '')\n#         desc = desc.replace('\"', '')\n#         param_dict['description'] = desc\n\n#         param_type = item[index_parameter_type - 1 : index_default_value - 2].replace('\"parameter_type\":', '')\n#         param_type = ast.literal_eval(param_type)\n#         param_dict['parameter_type'] = param_type\n\n#         default_value = item[index_default_value - 1 : index_optional - 2].replace('\"default_value\":', '')\n#         param_dict['default_value'] = default_value\n\n#         optional = item[index_optional - 1 :].replace('\"optional\":', '')\n#         param_dict['optional'] = optional\n\n#         params_dict[flags] = param_dict\n\n#     return params_dict\n\n# tool_name = \"BreachDepressions\"\n# print(wbt.tool_parameters(tool_name))\n\n\n# params = get_tool_params(tool_name)\n# print(params)\n# print(params.keys())\n\n# print(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))\n\n# lines = wbt.list_tools()\n# print(lines)\n\n# # for line in lines:\n# #     print(line)\n\n# print(len(lines))\n\n# parameter_types = []\n\n# for param in params:\n\n#     param_type = params[param]['parameter_type']\n#     if param_type not in parameter_types:\n#         parameter_types.append(param_type)\n\n\n# print(parameter_types)\n\n# thisset = {\"apple\", \"banana\", \"cherry\"}\n\n# thisset.add(\"orange\")\n\n# print(thisset)\n\n# tools = wbt.list_tools()\n# for index, tool in enumerate(sorted(tools)):\n#     print(\"{}: {}\".format(index, tool))\n\n# dem = \"/media/hdd/Dropbox/git/WhiteboxTools-ArcGIS/testdata/DEM.tif\"\n# output = \"/media/hdd/Dropbox/git/WhiteboxTools-ArcGIS/testdata/output.tif\"\n\n# wbt.run_tool(\"BreachDepressions\", '--dem=dem --output=output')\n\n# exe_path = \"/home/qiusheng/Downloads/WBT/whitebox_tools\"\n\n# cmd = exe_path + ' --run=BreachDepressions  --dem=\"/media/hdd/Dropbox/git/WhiteboxTools-ArcGIS/testdata/DEM.tif\" --output=\"/media/hdd/Dropbox/git/WhiteboxTools-ArcGIS/testdata/output.tif\" -v'\n# print(os.popen(cmd).read().rstrip())\n\n# ret = wbt.breach_depressions(dem, output)\n# print(ret)\n# print(type(ret))\n\n# def redirect_to_file(text):\n#     original = sys.stdout\n#     sys.stdout = open('/media/hdd/Dropbox/git/WhiteboxTools-ArcGIS/WBT/PRE/redirect.txt', 'w')\n#     # print('This is your redirected text:')\n#     # print(text)\n#     wbt.breach_depressions(dem, output)\n#     sys.stdout = original\n \n#     print('This string goes to stdout, NOT the file!')\n\n# redirect_to_file('Python rocks!')\n\n# https://goo.gl/bFo2tD\n\n# import sys\n# if sys.version_info < (3, 0): \n#     from StringIO import StringIO\n# else:\n#     from io import StringIO\n# old_stdout = sys.stdout\n# result = StringIO()\n# sys.stdout = result\n# # wbt.breach_depressions(dem, output)\n# # print(\"test string\")\n# sys.stdout = old_stdout\n# result_string = result.getvalue()\n# print(result_string)\n\n# print('--dem=\"/path/to/DEM.tif\"  --output=\"/path/to/output.tif\"')"
  },
  {
    "path": "WBT/PRE/whitebox_tools.py",
    "content": "#!/usr/bin/env python3\n''' This file is intended to be a helper for running whitebox-tools plugins from a Python script.\nSee whitebox_example.py for an example of how to use it.\n'''\n\n# This script is part of the WhiteboxTools geospatial library.\n# Authors: Dr. John Lindsay\n# Created: 28/11/2017\n# Last Modified: 09/12/2019\n# License: MIT\n\nfrom __future__ import print_function\nimport os\nfrom os import path\nimport sys\nimport platform\nimport re\n# import shutil\nfrom subprocess import CalledProcessError, Popen, PIPE, STDOUT\n\n\ndef default_callback(value):\n    ''' \n    A simple default callback that outputs using the print function. When\n    tools are called without providing a custom callback, this function\n    will be used to print to standard output.\n    '''\n    print(value)\n\n\ndef to_camelcase(name):\n    '''\n    Convert snake_case name to CamelCase name \n    '''\n    return ''.join(x.title() for x in name.split('_'))\n\n\ndef to_snakecase(name):\n    '''\n    Convert CamelCase name to snake_case name \n    '''\n    s1 = re.sub('(.)([A-Z][a-z]+)', r'\\1_\\2', name)\n    return re.sub('([a-z0-9])([A-Z])', r'\\1_\\2', s1).lower()\n\n\nclass WhiteboxTools(object):\n    ''' \n    An object for interfacing with the WhiteboxTools executable.\n    '''\n\n    def __init__(self):\n        if platform.system() == 'Windows':\n            self.ext = '.exe'\n        else:\n            self.ext = ''\n        self.exe_name = \"whitebox_tools{}\".format(self.ext)\n        # self.exe_path = os.path.dirname(shutil.which(\n        #     self.exe_name) or path.dirname(path.abspath(__file__)))\n        # self.exe_path = os.path.dirname(os.path.join(os.path.realpath(__file__)))\n        self.exe_path = path.dirname(path.abspath(__file__))\n        self.work_dir = \"\"\n        self.verbose = True\n        self.cancel_op = False\n        self.default_callback = default_callback\n\n    def set_whitebox_dir(self, path_str):\n        ''' \n        Sets the directory to the WhiteboxTools executable file.\n        '''\n        self.exe_path = path_str\n\n    def set_working_dir(self, path_str):\n        ''' \n        Sets the working directory, i.e. the directory in which\n        the data files are located. By setting the working \n        directory, tool input parameters that are files need only\n        specify the file name rather than the complete file path.\n        '''\n        self.work_dir = path.normpath(path_str)\n\n    def set_verbose_mode(self, val=True):\n        ''' \n        Sets verbose mode. If verbose mode is False, tools will not\n        print output messages. Tools will frequently provide substantial\n        feedback while they are operating, e.g. updating progress for \n        various sub-routines. When the user has scripted a workflow\n        that ties many tools in sequence, this level of tool output\n        can be problematic. By setting verbose mode to False, these\n        messages are suppressed and tools run as background processes.\n        '''\n        self.verbose = val\n\n    def run_tool(self, tool_name, args, callback=None):\n        ''' \n        Runs a tool and specifies tool arguments.\n        Returns 0 if completes without error.\n        Returns 1 if error encountered (details are sent to callback).\n        Returns 2 if process is cancelled by user.\n        '''\n        try:\n            if callback is None:\n                callback = self.default_callback\n\n            os.chdir(self.exe_path)\n            args2 = []\n            args2.append(\".\" + path.sep + self.exe_name)\n            args2.append(\"--run=\\\"{}\\\"\".format(to_camelcase(tool_name)))\n\n            if self.work_dir.strip() != \"\":\n                args2.append(\"--wd=\\\"{}\\\"\".format(self.work_dir))\n\n            for arg in args:\n                args2.append(arg)\n\n            # args_str = args_str[:-1]\n            # a.append(\"--args=\\\"{}\\\"\".format(args_str))\n\n            if self.verbose:\n                args2.append(\"-v\")\n\n            if self.verbose:\n                cl = \"\"\n                for v in args2:\n                    cl += v + \" \"\n                callback(cl.strip() + \"\\n\")\n\n            proc = Popen(args2, shell=False, stdout=PIPE,\n                         stderr=STDOUT, bufsize=1, universal_newlines=True)\n\n            while True:\n                line = proc.stdout.readline()\n                sys.stdout.flush()\n                if line != '':\n                    if not self.cancel_op:\n                        callback(line.strip())\n                    else:\n                        self.cancel_op = False\n                        proc.terminate()\n                        return 2\n\n                else:\n                    break\n\n            return 0\n        except (OSError, ValueError, CalledProcessError) as err:\n            callback(str(err))\n            return 1\n\n    def help(self):\n        ''' \n        Retrieves the help description for WhiteboxTools.\n        '''\n        try:\n            os.chdir(self.exe_path)\n            args = []\n            args.append(\".\" + os.path.sep + self.exe_name)\n            args.append(\"-h\")\n\n            proc = Popen(args, shell=False, stdout=PIPE,\n                         stderr=STDOUT, bufsize=1, universal_newlines=True)\n            ret = \"\"\n            while True:\n                line = proc.stdout.readline()\n                if line != '':\n                    ret += line\n                else:\n                    break\n\n            return ret\n        except (OSError, ValueError, CalledProcessError) as err:\n            return err\n\n    def license(self):\n        ''' \n        Retrieves the license information for WhiteboxTools.\n        '''\n        try:\n            os.chdir(self.exe_path)\n            args = []\n            args.append(\".\" + os.path.sep + self.exe_name)\n            args.append(\"--license\")\n\n            proc = Popen(args, shell=False, stdout=PIPE,\n                         stderr=STDOUT, bufsize=1, universal_newlines=True)\n            ret = \"\"\n            while True:\n                line = proc.stdout.readline()\n                if line != '':\n                    ret += line\n                else:\n                    break\n\n            return ret\n        except (OSError, ValueError, CalledProcessError) as err:\n            return err\n\n    def version(self):\n        ''' \n        Retrieves the version information for WhiteboxTools.\n        '''\n        try:\n            os.chdir(self.exe_path)\n            args = []\n            args.append(\".\" + os.path.sep + self.exe_name)\n            args.append(\"--version\")\n\n            proc = Popen(args, shell=False, stdout=PIPE,\n                         stderr=STDOUT, bufsize=1, universal_newlines=True)\n            ret = \"\"\n            while True:\n                line = proc.stdout.readline()\n                if line != '':\n                    ret += line\n                else:\n                    break\n\n            return ret\n        except (OSError, ValueError, CalledProcessError) as err:\n            return err\n\n    def tool_help(self, tool_name=''):\n        ''' \n        Retrieves the help description for a specific tool.\n        '''\n        try:\n            os.chdir(self.exe_path)\n            args = []\n            args.append(\".\" + os.path.sep + self.exe_name)\n            args.append(\"--toolhelp={}\".format(to_camelcase(tool_name)))\n\n            proc = Popen(args, shell=False, stdout=PIPE,\n                         stderr=STDOUT, bufsize=1, universal_newlines=True)\n            ret = \"\"\n            while True:\n                line = proc.stdout.readline()\n                if line != '':\n                    ret += line\n                else:\n                    break\n\n            return ret\n        except (OSError, ValueError, CalledProcessError) as err:\n            return err\n\n    def tool_parameters(self, tool_name):\n        ''' \n        Retrieves the tool parameter descriptions for a specific tool.\n        '''\n        try:\n            os.chdir(self.exe_path)\n            args = []\n            args.append(\".\" + os.path.sep + self.exe_name)\n            args.append(\"--toolparameters={}\".format(to_camelcase(tool_name)))\n\n            proc = Popen(args, shell=False, stdout=PIPE,\n                         stderr=STDOUT, bufsize=1, universal_newlines=True)\n            ret = \"\"\n            while True:\n                line = proc.stdout.readline()\n                if line != '':\n                    ret += line\n                else:\n                    break\n\n            return ret\n        except (OSError, ValueError, CalledProcessError) as err:\n            return err\n\n    def toolbox(self, tool_name=''):\n        ''' \n        Retrieve the toolbox for a specific tool.\n        '''\n        try:\n            os.chdir(self.exe_path)\n            args = []\n            args.append(\".\" + os.path.sep + self.exe_name)\n            args.append(\"--toolbox={}\".format(to_camelcase(tool_name)))\n\n            proc = Popen(args, shell=False, stdout=PIPE,\n                         stderr=STDOUT, bufsize=1, universal_newlines=True)\n            ret = \"\"\n            while True:\n                line = proc.stdout.readline()\n                if line != '':\n                    ret += line\n                else:\n                    break\n\n            return ret\n        except (OSError, ValueError, CalledProcessError) as err:\n            return err\n\n    def view_code(self, tool_name):\n        ''' \n        Opens a web browser to view the source code for a specific tool\n        on the projects source code repository.\n        '''\n        try:\n            os.chdir(self.exe_path)\n            args = []\n            args.append(\".\" + os.path.sep + self.exe_name)\n            args.append(\"--viewcode={}\".format(to_camelcase(tool_name)))\n\n            proc = Popen(args, shell=False, stdout=PIPE,\n                         stderr=STDOUT, bufsize=1, universal_newlines=True)\n            ret = \"\"\n            while True:\n                line = proc.stdout.readline()\n                if line != '':\n                    ret += line\n                else:\n                    break\n\n            return ret\n        except (OSError, ValueError, CalledProcessError) as err:\n            return err\n\n    def list_tools(self, keywords=[]):\n        ''' \n        Lists all available tools in WhiteboxTools.\n        '''\n        try:\n            os.chdir(self.exe_path)\n            args = []\n            args.append(\".\" + os.path.sep + self.exe_name)\n            args.append(\"--listtools\")\n            if len(keywords) > 0:\n                for kw in keywords:\n                    args.append(kw)\n\n            proc = Popen(args, shell=False, stdout=PIPE,\n                         stderr=STDOUT, bufsize=1, universal_newlines=True)\n            ret = {}\n            line = proc.stdout.readline()  # skip number of available tools header\n            while True:\n                line = proc.stdout.readline()\n                if line != '':\n                    if line.strip() != '':\n                        name, descr = line.split(':')\n                        ret[to_snakecase(name.strip())] = descr.strip()\n                else:\n                    break\n\n            return ret\n        except (OSError, ValueError, CalledProcessError) as err:\n            return err\n\n    ########################################################################\n    # The following methods are convenience methods for each available tool.\n    # This needs updating whenever new tools are added to the WhiteboxTools\n    # library. They can be generated automatically using the\n    # whitebox_plugin_generator.py script. It would also be possible to\n    # discover plugins at runtime and monkey-patch their methods using\n    # MethodType. However, this would not be as useful since it would\n    # restrict the ability for text editors and IDEs to use autocomplete.\n    ########################################################################\n\n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    ##############\n    # Data Tools #\n    ##############\n\n    def add_point_coordinates_to_table(self, i, callback=None):\n        \"\"\"Modifies the attribute table of a point vector by adding fields containing each point's X and Y coordinates.\n\n        Keyword arguments:\n\n        i -- Input vector Points file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('add_point_coordinates_to_table', args, callback) # returns 1 if error\n\n    def clean_vector(self, i, output, callback=None):\n        \"\"\"Removes null features and lines/polygons with fewer than the required number of vertices.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('clean_vector', args, callback) # returns 1 if error\n\n    def convert_nodata_to_zero(self, i, output, callback=None):\n        \"\"\"Converts nodata values in a raster to zero.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('convert_nodata_to_zero', args, callback) # returns 1 if error\n\n    def convert_raster_format(self, i, output, callback=None):\n        \"\"\"Converts raster data from one format to another.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('convert_raster_format', args, callback) # returns 1 if error\n\n    def csv_points_to_vector(self, i, output, xfield=0, yfield=1, epsg=None, callback=None):\n        \"\"\"Converts a CSV text file to vector points.\n\n        Keyword arguments:\n\n        i -- Input CSV file (i.e. source of data to be imported). \n        output -- Output vector file. \n        xfield -- X field number (e.g. 0 for first field). \n        yfield -- Y field number (e.g. 1 for second field). \n        epsg -- EPSG projection (e.g. 2958). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--xfield={}\".format(xfield))\n        args.append(\"--yfield={}\".format(yfield))\n        if epsg is not None: args.append(\"--epsg='{}'\".format(epsg))\n        return self.run_tool('csv_points_to_vector', args, callback) # returns 1 if error\n\n    def export_table_to_csv(self, i, output, headers=True, callback=None):\n        \"\"\"Exports an attribute table to a CSV text file.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output raster file. \n        headers -- Export field names as file header?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if headers: args.append(\"--headers\")\n        return self.run_tool('export_table_to_csv', args, callback) # returns 1 if error\n\n    def join_tables(self, input1, pkey, input2, fkey, import_field, callback=None):\n        \"\"\"Merge a vector's attribute table with another table based on a common field.\n\n        Keyword arguments:\n\n        input1 -- Input primary vector file (i.e. the table to be modified). \n        pkey -- Primary key field. \n        input2 -- Input foreign vector file (i.e. source of data to be imported). \n        fkey -- Foreign key field. \n        import_field -- Imported field (all fields will be imported if not specified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--pkey='{}'\".format(pkey))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--fkey='{}'\".format(fkey))\n        args.append(\"--import_field='{}'\".format(import_field))\n        return self.run_tool('join_tables', args, callback) # returns 1 if error\n\n    def lines_to_polygons(self, i, output, callback=None):\n        \"\"\"Converts vector polylines to polygons.\n\n        Keyword arguments:\n\n        i -- Input vector line file. \n        output -- Output vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('lines_to_polygons', args, callback) # returns 1 if error\n\n    def merge_table_with_csv(self, i, pkey, csv, fkey, import_field=None, callback=None):\n        \"\"\"Merge a vector's attribute table with a table contained within a CSV text file.\n\n        Keyword arguments:\n\n        i -- Input primary vector file (i.e. the table to be modified). \n        pkey -- Primary key field. \n        csv -- Input CSV file (i.e. source of data to be imported). \n        fkey -- Foreign key field. \n        import_field -- Imported field (all fields will be imported if not specified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--pkey='{}'\".format(pkey))\n        args.append(\"--csv='{}'\".format(csv))\n        args.append(\"--fkey='{}'\".format(fkey))\n        if import_field is not None: args.append(\"--import_field='{}'\".format(import_field))\n        return self.run_tool('merge_table_with_csv', args, callback) # returns 1 if error\n\n    def merge_vectors(self, inputs, output, callback=None):\n        \"\"\"Combines two or more input vectors of the same ShapeType creating a single, new output vector.\n\n        Keyword arguments:\n\n        inputs -- Input vector files. \n        output -- Output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('merge_vectors', args, callback) # returns 1 if error\n\n    def modify_no_data_value(self, i, new_value=\"-32768.0\", callback=None):\n        \"\"\"Converts nodata values in a raster to zero.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        new_value -- New NoData value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--new_value={}\".format(new_value))\n        return self.run_tool('modify_no_data_value', args, callback) # returns 1 if error\n\n    def multi_part_to_single_part(self, i, output, exclude_holes=True, callback=None):\n        \"\"\"Converts a vector file containing multi-part features into a vector containing only single-part features.\n\n        Keyword arguments:\n\n        i -- Input vector line or polygon file. \n        output -- Output vector line or polygon file. \n        exclude_holes -- Exclude hole parts from the feature splitting? (holes will continue to belong to their features in output.). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if exclude_holes: args.append(\"--exclude_holes\")\n        return self.run_tool('multi_part_to_single_part', args, callback) # returns 1 if error\n\n    def new_raster_from_base(self, base, output, value=\"nodata\", data_type=\"float\", callback=None):\n        \"\"\"Creates a new raster using a base image.\n\n        Keyword arguments:\n\n        base -- Input base raster file. \n        output -- Output raster file. \n        value -- Constant value to fill raster with; either 'nodata' or numeric value. \n        data_type -- Output raster data type; options include 'double' (64-bit), 'float' (32-bit), and 'integer' (signed 16-bit) (default is 'float'). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--base='{}'\".format(base))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--value={}\".format(value))\n        args.append(\"--data_type={}\".format(data_type))\n        return self.run_tool('new_raster_from_base', args, callback) # returns 1 if error\n\n    def polygons_to_lines(self, i, output, callback=None):\n        \"\"\"Converts vector polygons to polylines.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        output -- Output vector lines file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('polygons_to_lines', args, callback) # returns 1 if error\n\n    def print_geo_tiff_tags(self, i, callback=None):\n        \"\"\"Prints the tags within a GeoTIFF.\n\n        Keyword arguments:\n\n        i -- Input GeoTIFF file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('print_geo_tiff_tags', args, callback) # returns 1 if error\n\n    def raster_to_vector_lines(self, i, output, callback=None):\n        \"\"\"Converts a raster lines features into a vector of the POLYLINE shapetype.\n\n        Keyword arguments:\n\n        i -- Input raster lines file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('raster_to_vector_lines', args, callback) # returns 1 if error\n\n    def raster_to_vector_points(self, i, output, callback=None):\n        \"\"\"Converts a raster dataset to a vector of the POINT shapetype.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output vector points file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('raster_to_vector_points', args, callback) # returns 1 if error\n\n    def raster_to_vector_polygons(self, i, output, callback=None):\n        \"\"\"Converts a raster dataset to a vector of the POLYGON shapetype.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output vector polygons file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('raster_to_vector_polygons', args, callback) # returns 1 if error\n\n    def reinitialize_attribute_table(self, i, callback=None):\n        \"\"\"Reinitializes a vector's attribute table deleting all fields but the feature ID (FID).\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('reinitialize_attribute_table', args, callback) # returns 1 if error\n\n    def remove_polygon_holes(self, i, output, callback=None):\n        \"\"\"Removes holes within the features of a vector polygon file.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        output -- Output vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('remove_polygon_holes', args, callback) # returns 1 if error\n\n    def set_nodata_value(self, i, output, back_value=0.0, callback=None):\n        \"\"\"Assign a specified value in an input image to the NoData value.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        back_value -- Background value to set to nodata. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--back_value={}\".format(back_value))\n        return self.run_tool('set_nodata_value', args, callback) # returns 1 if error\n\n    def single_part_to_multi_part(self, i, output, field=None, callback=None):\n        \"\"\"Converts a vector file containing multi-part features into a vector containing only single-part features.\n\n        Keyword arguments:\n\n        i -- Input vector line or polygon file. \n        field -- Grouping ID field name in attribute table. \n        output -- Output vector line or polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if field is not None: args.append(\"--field='{}'\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('single_part_to_multi_part', args, callback) # returns 1 if error\n\n    def vector_lines_to_raster(self, i, output, field=\"FID\", nodata=True, cell_size=None, base=None, callback=None):\n        \"\"\"Converts a vector containing polylines into a raster.\n\n        Keyword arguments:\n\n        i -- Input vector lines file. \n        field -- Input field name in attribute table. \n        output -- Output raster file. \n        nodata -- Background value to set to NoData. Without this flag, it will be set to 0.0. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field={}\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        if nodata: args.append(\"--nodata\")\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        return self.run_tool('vector_lines_to_raster', args, callback) # returns 1 if error\n\n    def vector_points_to_raster(self, i, output, field=\"FID\", assign=\"last\", nodata=True, cell_size=None, base=None, callback=None):\n        \"\"\"Converts a vector containing points into a raster.\n\n        Keyword arguments:\n\n        i -- Input vector Points file. \n        field -- Input field name in attribute table. \n        output -- Output raster file. \n        assign -- Assignment operation, where multiple points are in the same grid cell; options include 'first', 'last' (default), 'min', 'max', 'sum'. \n        nodata -- Background value to set to NoData. Without this flag, it will be set to 0.0. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field={}\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--assign={}\".format(assign))\n        if nodata: args.append(\"--nodata\")\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        return self.run_tool('vector_points_to_raster', args, callback) # returns 1 if error\n\n    def vector_polygons_to_raster(self, i, output, field=\"FID\", nodata=True, cell_size=None, base=None, callback=None):\n        \"\"\"Converts a vector containing polygons into a raster.\n\n        Keyword arguments:\n\n        i -- Input vector polygons file. \n        field -- Input field name in attribute table. \n        output -- Output raster file. \n        nodata -- Background value to set to NoData. Without this flag, it will be set to 0.0. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field={}\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        if nodata: args.append(\"--nodata\")\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        return self.run_tool('vector_polygons_to_raster', args, callback) # returns 1 if error\n\n    ################\n    # GIS Analysis #\n    ################\n\n    def aggregate_raster(self, i, output, agg_factor=2, type=\"mean\", callback=None):\n        \"\"\"Aggregates a raster to a lower resolution.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        agg_factor -- Aggregation factor, in pixels. \n        type -- Statistic used to fill output pixels. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--agg_factor={}\".format(agg_factor))\n        args.append(\"--type={}\".format(type))\n        return self.run_tool('aggregate_raster', args, callback) # returns 1 if error\n\n    def block_maximum_gridding(self, i, field, output, use_z=False, cell_size=None, base=None, callback=None):\n        \"\"\"Creates a raster grid based on a set of vector points and assigns grid values using a block maximum scheme.\n\n        Keyword arguments:\n\n        i -- Input vector Points file. \n        field -- Input field name in attribute table. \n        use_z -- Use z-coordinate instead of field?. \n        output -- Output raster file. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field='{}'\".format(field))\n        if use_z: args.append(\"--use_z\")\n        args.append(\"--output='{}'\".format(output))\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        return self.run_tool('block_maximum_gridding', args, callback) # returns 1 if error\n\n    def block_minimum_gridding(self, i, field, output, use_z=False, cell_size=None, base=None, callback=None):\n        \"\"\"Creates a raster grid based on a set of vector points and assigns grid values using a block minimum scheme.\n\n        Keyword arguments:\n\n        i -- Input vector Points file. \n        field -- Input field name in attribute table. \n        use_z -- Use z-coordinate instead of field?. \n        output -- Output raster file. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field='{}'\".format(field))\n        if use_z: args.append(\"--use_z\")\n        args.append(\"--output='{}'\".format(output))\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        return self.run_tool('block_minimum_gridding', args, callback) # returns 1 if error\n\n    def centroid(self, i, output, text_output=False, callback=None):\n        \"\"\"Calculates the centroid, or average location, of raster polygon objects.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        text_output -- Optional text output. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if text_output: args.append(\"--text_output\")\n        return self.run_tool('centroid', args, callback) # returns 1 if error\n\n    def centroid_vector(self, i, output, callback=None):\n        \"\"\"Identifes the centroid point of a vector polyline or polygon feature or a group of vector points.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('centroid_vector', args, callback) # returns 1 if error\n\n    def clump(self, i, output, diag=True, zero_back=False, callback=None):\n        \"\"\"Groups cells that form discrete areas, assigning them unique identifiers.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        diag -- Flag indicating whether diagonal connections should be considered. \n        zero_back -- Flag indicating whether zero values should be treated as a background. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if diag: args.append(\"--diag\")\n        if zero_back: args.append(\"--zero_back\")\n        return self.run_tool('clump', args, callback) # returns 1 if error\n\n    def construct_vector_tin(self, i, output, field=None, use_z=False, max_triangle_edge_length=None, callback=None):\n        \"\"\"Creates a vector triangular irregular network (TIN) for a set of vector points.\n\n        Keyword arguments:\n\n        i -- Input vector points file. \n        field -- Input field name in attribute table. \n        use_z -- Use the 'z' dimension of the Shapefile's geometry instead of an attribute field?. \n        output -- Output vector polygon file. \n        max_triangle_edge_length -- Optional maximum triangle edge length; triangles larger than this size will not be gridded. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if field is not None: args.append(\"--field='{}'\".format(field))\n        if use_z: args.append(\"--use_z\")\n        args.append(\"--output='{}'\".format(output))\n        if max_triangle_edge_length is not None: args.append(\"--max_triangle_edge_length='{}'\".format(max_triangle_edge_length))\n        return self.run_tool('construct_vector_tin', args, callback) # returns 1 if error\n\n    def create_hexagonal_vector_grid(self, i, output, width, orientation=\"horizontal\", callback=None):\n        \"\"\"Creates a hexagonal vector grid.\n\n        Keyword arguments:\n\n        i -- Input base file. \n        output -- Output vector polygon file. \n        width -- The grid cell width. \n        orientation -- Grid Orientation, 'horizontal' or 'vertical'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--width='{}'\".format(width))\n        args.append(\"--orientation={}\".format(orientation))\n        return self.run_tool('create_hexagonal_vector_grid', args, callback) # returns 1 if error\n\n    def create_plane(self, base, output, gradient=15.0, aspect=90.0, constant=0.0, callback=None):\n        \"\"\"Creates a raster image based on the equation for a simple plane.\n\n        Keyword arguments:\n\n        base -- Input base raster file. \n        output -- Output raster file. \n        gradient -- Slope gradient in degrees (-85.0 to 85.0). \n        aspect -- Aspect (direction) in degrees clockwise from north (0.0-360.0). \n        constant -- Constant value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--base='{}'\".format(base))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--gradient={}\".format(gradient))\n        args.append(\"--aspect={}\".format(aspect))\n        args.append(\"--constant={}\".format(constant))\n        return self.run_tool('create_plane', args, callback) # returns 1 if error\n\n    def create_rectangular_vector_grid(self, i, output, width, height, xorig=0, yorig=0, callback=None):\n        \"\"\"Creates a rectangular vector grid.\n\n        Keyword arguments:\n\n        i -- Input base file. \n        output -- Output vector polygon file. \n        width -- The grid cell width. \n        height -- The grid cell height. \n        xorig -- The grid origin x-coordinate. \n        yorig -- The grid origin y-coordinate. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--width='{}'\".format(width))\n        args.append(\"--height='{}'\".format(height))\n        args.append(\"--xorig={}\".format(xorig))\n        args.append(\"--yorig={}\".format(yorig))\n        return self.run_tool('create_rectangular_vector_grid', args, callback) # returns 1 if error\n\n    def dissolve(self, i, output, field=None, snap=0.0, callback=None):\n        \"\"\"Removes the interior, or shared, boundaries within a vector polygon coverage.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        field -- Dissolve field attribute (optional). \n        output -- Output vector file. \n        snap -- Snap tolerance. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if field is not None: args.append(\"--field='{}'\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--snap={}\".format(snap))\n        return self.run_tool('dissolve', args, callback) # returns 1 if error\n\n    def eliminate_coincident_points(self, i, output, tolerance, callback=None):\n        \"\"\"Removes any coincident, or nearly coincident, points from a vector points file.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output vector polygon file. \n        tolerance -- The distance tolerance for points. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--tolerance='{}'\".format(tolerance))\n        return self.run_tool('eliminate_coincident_points', args, callback) # returns 1 if error\n\n    def extend_vector_lines(self, i, output, dist, extend=\"both ends\", callback=None):\n        \"\"\"Extends vector lines by a specified distance.\n\n        Keyword arguments:\n\n        i -- Input vector polyline file. \n        output -- Output vector polyline file. \n        dist -- The distance to extend. \n        extend -- Extend direction, 'both ends' (default), 'line start', 'line end'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--dist='{}'\".format(dist))\n        args.append(\"--extend={}\".format(extend))\n        return self.run_tool('extend_vector_lines', args, callback) # returns 1 if error\n\n    def extract_nodes(self, i, output, callback=None):\n        \"\"\"Converts vector lines or polygons into vertex points.\n\n        Keyword arguments:\n\n        i -- Input vector lines or polygon file. \n        output -- Output vector points file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('extract_nodes', args, callback) # returns 1 if error\n\n    def extract_raster_values_at_points(self, inputs, points, out_text=False, callback=None):\n        \"\"\"Extracts the values of raster(s) at vector point locations.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        points -- Input vector points file. \n        out_text -- Output point values as text? Otherwise, the only output is to to the points file's attribute table. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--points='{}'\".format(points))\n        if out_text: args.append(\"--out_text\")\n        return self.run_tool('extract_raster_values_at_points', args, callback) # returns 1 if error\n\n    def find_lowest_or_highest_points(self, i, output, out_type=\"lowest\", callback=None):\n        \"\"\"Locates the lowest and/or highest valued cells in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output vector points file. \n        out_type -- Output type; one of 'area' (default) and 'volume'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--out_type={}\".format(out_type))\n        return self.run_tool('find_lowest_or_highest_points', args, callback) # returns 1 if error\n\n    def idw_interpolation(self, i, field, output, use_z=False, weight=2.0, radius=None, min_points=None, cell_size=None, base=None, callback=None):\n        \"\"\"Interpolates vector points into a raster surface using an inverse-distance weighted scheme.\n\n        Keyword arguments:\n\n        i -- Input vector Points file. \n        field -- Input field name in attribute table. \n        use_z -- Use z-coordinate instead of field?. \n        output -- Output raster file. \n        weight -- IDW weight value. \n        radius -- Search Radius in map units. \n        min_points -- Minimum number of points. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field='{}'\".format(field))\n        if use_z: args.append(\"--use_z\")\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--weight={}\".format(weight))\n        if radius is not None: args.append(\"--radius='{}'\".format(radius))\n        if min_points is not None: args.append(\"--min_points='{}'\".format(min_points))\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        return self.run_tool('idw_interpolation', args, callback) # returns 1 if error\n\n    def layer_footprint(self, i, output, callback=None):\n        \"\"\"Creates a vector polygon footprint of the area covered by a raster grid or vector layer.\n\n        Keyword arguments:\n\n        i -- Input raster or vector file. \n        output -- Output vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('layer_footprint', args, callback) # returns 1 if error\n\n    def medoid(self, i, output, callback=None):\n        \"\"\"Calculates the medoid for a series of vector features contained in a shapefile.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('medoid', args, callback) # returns 1 if error\n\n    def minimum_bounding_box(self, i, output, criterion=\"area\", features=True, callback=None):\n        \"\"\"Creates a vector minimum bounding rectangle around vector features.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output vector polygon file. \n        criterion -- Minimization criterion; options include 'area' (default), 'length', 'width', and 'perimeter'. \n        features -- Find the minimum bounding rectangles around each individual vector feature. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--criterion={}\".format(criterion))\n        if features: args.append(\"--features\")\n        return self.run_tool('minimum_bounding_box', args, callback) # returns 1 if error\n\n    def minimum_bounding_circle(self, i, output, features=True, callback=None):\n        \"\"\"Delineates the minimum bounding circle (i.e. smallest enclosing circle) for a group of vectors.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output vector polygon file. \n        features -- Find the minimum bounding circle around each individual vector feature. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if features: args.append(\"--features\")\n        return self.run_tool('minimum_bounding_circle', args, callback) # returns 1 if error\n\n    def minimum_bounding_envelope(self, i, output, features=True, callback=None):\n        \"\"\"Creates a vector axis-aligned minimum bounding rectangle (envelope) around vector features.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output vector polygon file. \n        features -- Find the minimum bounding envelop around each individual vector feature. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if features: args.append(\"--features\")\n        return self.run_tool('minimum_bounding_envelope', args, callback) # returns 1 if error\n\n    def minimum_convex_hull(self, i, output, features=True, callback=None):\n        \"\"\"Creates a vector convex polygon around vector features.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output vector polygon file. \n        features -- Find the hulls around each vector feature. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if features: args.append(\"--features\")\n        return self.run_tool('minimum_convex_hull', args, callback) # returns 1 if error\n\n    def natural_neighbour_interpolation(self, i, output, field=None, use_z=False, cell_size=None, base=None, clip=True, callback=None):\n        \"\"\"Creates a raster grid based on Sibson's natural neighbour method.\n\n        Keyword arguments:\n\n        i -- Input vector points file. \n        field -- Input field name in attribute table. \n        use_z -- Use the 'z' dimension of the Shapefile's geometry instead of an attribute field?. \n        output -- Output raster file. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        clip -- Clip the data to the convex hull of the points?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if field is not None: args.append(\"--field='{}'\".format(field))\n        if use_z: args.append(\"--use_z\")\n        args.append(\"--output='{}'\".format(output))\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        if clip: args.append(\"--clip\")\n        return self.run_tool('natural_neighbour_interpolation', args, callback) # returns 1 if error\n\n    def nearest_neighbour_gridding(self, i, field, output, use_z=False, cell_size=None, base=None, max_dist=None, callback=None):\n        \"\"\"Creates a raster grid based on a set of vector points and assigns grid values using the nearest neighbour.\n\n        Keyword arguments:\n\n        i -- Input vector Points file. \n        field -- Input field name in attribute table. \n        use_z -- Use z-coordinate instead of field?. \n        output -- Output raster file. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        max_dist -- Maximum search distance (optional). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field='{}'\".format(field))\n        if use_z: args.append(\"--use_z\")\n        args.append(\"--output='{}'\".format(output))\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        if max_dist is not None: args.append(\"--max_dist='{}'\".format(max_dist))\n        return self.run_tool('nearest_neighbour_gridding', args, callback) # returns 1 if error\n\n    def polygon_area(self, i, callback=None):\n        \"\"\"Calculates the area of vector polygons.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('polygon_area', args, callback) # returns 1 if error\n\n    def polygon_long_axis(self, i, output, callback=None):\n        \"\"\"This tool can be used to map the long axis of polygon features.\n\n        Keyword arguments:\n\n        i -- Input vector polygons file. \n        output -- Output vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('polygon_long_axis', args, callback) # returns 1 if error\n\n    def polygon_perimeter(self, i, callback=None):\n        \"\"\"Calculates the perimeter of vector polygons.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('polygon_perimeter', args, callback) # returns 1 if error\n\n    def polygon_short_axis(self, i, output, callback=None):\n        \"\"\"This tool can be used to map the short axis of polygon features.\n\n        Keyword arguments:\n\n        i -- Input vector polygons file. \n        output -- Output vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('polygon_short_axis', args, callback) # returns 1 if error\n\n    def radial_basis_function_interpolation(self, i, field, output, use_z=False, radius=None, min_points=None, func_type=\"ThinPlateSpline\", poly_order=\"none\", weight=0.1, cell_size=None, base=None, callback=None):\n        \"\"\"Interpolates vector points into a raster surface using a radial basis function scheme.\n\n        Keyword arguments:\n\n        i -- Input vector points file. \n        field -- Input field name in attribute table. \n        use_z -- Use z-coordinate instead of field?. \n        output -- Output raster file. \n        radius -- Search Radius (in map units). \n        min_points -- Minimum number of points. \n        func_type -- Radial basis function type; options are 'ThinPlateSpline' (default), 'PolyHarmonic', 'Gaussian', 'MultiQuadric', 'InverseMultiQuadric'. \n        poly_order -- Polynomial order; options are 'none' (default), 'constant', 'affine'. \n        weight -- Weight parameter used in basis function. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field='{}'\".format(field))\n        if use_z: args.append(\"--use_z\")\n        args.append(\"--output='{}'\".format(output))\n        if radius is not None: args.append(\"--radius='{}'\".format(radius))\n        if min_points is not None: args.append(\"--min_points='{}'\".format(min_points))\n        args.append(\"--func_type={}\".format(func_type))\n        args.append(\"--poly_order={}\".format(poly_order))\n        args.append(\"--weight={}\".format(weight))\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        return self.run_tool('radial_basis_function_interpolation', args, callback) # returns 1 if error\n\n    def raster_area(self, i, output=None, out_text=False, units=\"grid cells\", zero_back=False, callback=None):\n        \"\"\"Calculates the area of polygons or classes within a raster image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        out_text -- Would you like to output polygon areas to text?. \n        units -- Area units; options include 'grid cells' and 'map units'. \n        zero_back -- Flag indicating whether zero values should be treated as a background. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        if out_text: args.append(\"--out_text\")\n        args.append(\"--units={}\".format(units))\n        if zero_back: args.append(\"--zero_back\")\n        return self.run_tool('raster_area', args, callback) # returns 1 if error\n\n    def raster_cell_assignment(self, i, output, assign=\"column\", callback=None):\n        \"\"\"Assign row or column number to cells.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        assign -- Which variable would you like to assign to grid cells? Options include 'column', 'row', 'x', and 'y'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--assign={}\".format(assign))\n        return self.run_tool('raster_cell_assignment', args, callback) # returns 1 if error\n\n    def raster_perimeter(self, i, output=None, out_text=False, units=\"grid cells\", zero_back=False, callback=None):\n        \"\"\"Calculates the perimeters of polygons or classes within a raster image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        out_text -- Would you like to output polygon areas to text?. \n        units -- Area units; options include 'grid cells' and 'map units'. \n        zero_back -- Flag indicating whether zero values should be treated as a background. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        if out_text: args.append(\"--out_text\")\n        args.append(\"--units={}\".format(units))\n        if zero_back: args.append(\"--zero_back\")\n        return self.run_tool('raster_perimeter', args, callback) # returns 1 if error\n\n    def reclass(self, i, output, reclass_vals, assign_mode=False, callback=None):\n        \"\"\"Reclassifies the values in a raster image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        reclass_vals -- Reclassification triplet values (new value; from value; to less than), e.g. '0.0;0.0;1.0;1.0;1.0;2.0'. \n        assign_mode -- Optional Boolean flag indicating whether to operate in assign mode, reclass_vals values are interpreted as new value; old value pairs. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--reclass_vals='{}'\".format(reclass_vals))\n        if assign_mode: args.append(\"--assign_mode\")\n        return self.run_tool('reclass', args, callback) # returns 1 if error\n\n    def reclass_equal_interval(self, i, output, interval=10.0, start_val=None, end_val=None, callback=None):\n        \"\"\"Reclassifies the values in a raster image based on equal-ranges.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        interval -- Class interval size. \n        start_val -- Optional starting value (default is input minimum value). \n        end_val -- Optional ending value (default is input maximum value). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--interval={}\".format(interval))\n        if start_val is not None: args.append(\"--start_val='{}'\".format(start_val))\n        if end_val is not None: args.append(\"--end_val='{}'\".format(end_val))\n        return self.run_tool('reclass_equal_interval', args, callback) # returns 1 if error\n\n    def reclass_from_file(self, i, reclass_file, output, callback=None):\n        \"\"\"Reclassifies the values in a raster image using reclass ranges in a text file.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        reclass_file -- Input text file containing reclass ranges. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--reclass_file='{}'\".format(reclass_file))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('reclass_from_file', args, callback) # returns 1 if error\n\n    def smooth_vectors(self, i, output, filter=3, callback=None):\n        \"\"\"Smooths a vector coverage of either a POLYLINE or POLYGON base ShapeType.\n\n        Keyword arguments:\n\n        i -- Input vector POLYLINE or POLYGON file. \n        output -- Output vector file. \n        filter -- The filter size, any odd integer greater than or equal to 3; default is 3. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        return self.run_tool('smooth_vectors', args, callback) # returns 1 if error\n\n    def tin_gridding(self, i, output, field=None, use_z=False, resolution=None, base=None, max_triangle_edge_length=None, callback=None):\n        \"\"\"Creates a raster grid based on a triangular irregular network (TIN) fitted to vector points.\n\n        Keyword arguments:\n\n        i -- Input vector points file. \n        field -- Input field name in attribute table. \n        use_z -- Use the 'z' dimension of the Shapefile's geometry instead of an attribute field?. \n        output -- Output raster file. \n        resolution -- Output raster's grid resolution. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        max_triangle_edge_length -- Optional maximum triangle edge length; triangles larger than this size will not be gridded. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if field is not None: args.append(\"--field='{}'\".format(field))\n        if use_z: args.append(\"--use_z\")\n        args.append(\"--output='{}'\".format(output))\n        if resolution is not None: args.append(\"--resolution='{}'\".format(resolution))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        if max_triangle_edge_length is not None: args.append(\"--max_triangle_edge_length='{}'\".format(max_triangle_edge_length))\n        return self.run_tool('tin_gridding', args, callback) # returns 1 if error\n\n    def vector_hex_binning(self, i, output, width, orientation=\"horizontal\", callback=None):\n        \"\"\"Hex-bins a set of vector points.\n\n        Keyword arguments:\n\n        i -- Input base file. \n        output -- Output vector polygon file. \n        width -- The grid cell width. \n        orientation -- Grid Orientation, 'horizontal' or 'vertical'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--width='{}'\".format(width))\n        args.append(\"--orientation={}\".format(orientation))\n        return self.run_tool('vector_hex_binning', args, callback) # returns 1 if error\n\n    def voronoi_diagram(self, i, output, callback=None):\n        \"\"\"Creates a vector Voronoi diagram for a set of vector points.\n\n        Keyword arguments:\n\n        i -- Input vector points file. \n        output -- Output vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('voronoi_diagram', args, callback) # returns 1 if error\n\n    ###############################\n    # GIS Analysis/Distance Tools #\n    ###############################\n\n    def buffer_raster(self, i, output, size, gridcells=False, callback=None):\n        \"\"\"Maps a distance-based buffer around each non-background (non-zero/non-nodata) grid cell in an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        size -- Buffer size. \n        gridcells -- Optional flag to indicate that the 'size' threshold should be measured in grid cells instead of the default map units. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--size='{}'\".format(size))\n        if gridcells: args.append(\"--gridcells\")\n        return self.run_tool('buffer_raster', args, callback) # returns 1 if error\n\n    def cost_allocation(self, source, backlink, output, callback=None):\n        \"\"\"Identifies the source cell to which each grid cell is connected by a least-cost pathway in a cost-distance analysis.\n\n        Keyword arguments:\n\n        source -- Input source raster file. \n        backlink -- Input backlink raster file generated by the cost-distance tool. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--source='{}'\".format(source))\n        args.append(\"--backlink='{}'\".format(backlink))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('cost_allocation', args, callback) # returns 1 if error\n\n    def cost_distance(self, source, cost, out_accum, out_backlink, callback=None):\n        \"\"\"Performs cost-distance accumulation on a cost surface and a group of source cells.\n\n        Keyword arguments:\n\n        source -- Input source raster file. \n        cost -- Input cost (friction) raster file. \n        out_accum -- Output cost accumulation raster file. \n        out_backlink -- Output backlink raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--source='{}'\".format(source))\n        args.append(\"--cost='{}'\".format(cost))\n        args.append(\"--out_accum='{}'\".format(out_accum))\n        args.append(\"--out_backlink='{}'\".format(out_backlink))\n        return self.run_tool('cost_distance', args, callback) # returns 1 if error\n\n    def cost_pathway(self, destination, backlink, output, zero_background=False, callback=None):\n        \"\"\"Performs cost-distance pathway analysis using a series of destination grid cells.\n\n        Keyword arguments:\n\n        destination -- Input destination raster file. \n        backlink -- Input backlink raster file generated by the cost-distance tool. \n        output -- Output cost pathway raster file. \n        zero_background -- Flag indicating whether zero values should be treated as a background. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--destination='{}'\".format(destination))\n        args.append(\"--backlink='{}'\".format(backlink))\n        args.append(\"--output='{}'\".format(output))\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('cost_pathway', args, callback) # returns 1 if error\n\n    def euclidean_allocation(self, i, output, callback=None):\n        \"\"\"Assigns grid cells in the output raster the value of the nearest target cell in the input image, measured by the Shih and Wu (2004) Euclidean distance transform.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('euclidean_allocation', args, callback) # returns 1 if error\n\n    def euclidean_distance(self, i, output, callback=None):\n        \"\"\"Calculates the Shih and Wu (2004) Euclidean distance transform.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('euclidean_distance', args, callback) # returns 1 if error\n\n    ##############################\n    # GIS Analysis/Overlay Tools #\n    ##############################\n\n    def average_overlay(self, inputs, output, callback=None):\n        \"\"\"Calculates the average for each grid cell from a group of raster images.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('average_overlay', args, callback) # returns 1 if error\n\n    def clip(self, i, clip, output, callback=None):\n        \"\"\"Extract all the features, or parts of features, that overlap with the features of the clip vector.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        clip -- Input clip polygon vector file. \n        output -- Output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--clip='{}'\".format(clip))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('clip', args, callback) # returns 1 if error\n\n    def clip_raster_to_polygon(self, i, polygons, output, maintain_dimensions=False, callback=None):\n        \"\"\"Clips a raster to a vector polygon.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        polygons -- Input vector polygons file. \n        output -- Output raster file. \n        maintain_dimensions -- Maintain input raster dimensions?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--polygons='{}'\".format(polygons))\n        args.append(\"--output='{}'\".format(output))\n        if maintain_dimensions: args.append(\"--maintain_dimensions\")\n        return self.run_tool('clip_raster_to_polygon', args, callback) # returns 1 if error\n\n    def count_if(self, inputs, output, value, callback=None):\n        \"\"\"Counts the number of occurrences of a specified value in a cell-stack of rasters.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        value -- Search value (e.g. countif value = 5.0). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--value='{}'\".format(value))\n        return self.run_tool('count_if', args, callback) # returns 1 if error\n\n    def difference(self, i, overlay, output, callback=None):\n        \"\"\"Outputs the features that occur in one of the two vector inputs but not both, i.e. no overlapping features.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        overlay -- Input overlay vector file. \n        output -- Output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--overlay='{}'\".format(overlay))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('difference', args, callback) # returns 1 if error\n\n    def erase(self, i, erase, output, callback=None):\n        \"\"\"Removes all the features, or parts of features, that overlap with the features of the erase vector polygon.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        erase -- Input erase polygon vector file. \n        output -- Output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--erase='{}'\".format(erase))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('erase', args, callback) # returns 1 if error\n\n    def erase_polygon_from_raster(self, i, polygons, output, callback=None):\n        \"\"\"Erases (cuts out) a vector polygon from a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        polygons -- Input vector polygons file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--polygons='{}'\".format(polygons))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('erase_polygon_from_raster', args, callback) # returns 1 if error\n\n    def highest_position(self, inputs, output, callback=None):\n        \"\"\"Identifies the stack position of the maximum value within a raster stack on a cell-by-cell basis.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('highest_position', args, callback) # returns 1 if error\n\n    def intersect(self, i, overlay, output, snap=0.0, callback=None):\n        \"\"\"Identifies the parts of features in common between two input vector layers.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        overlay -- Input overlay vector file. \n        output -- Output vector file. \n        snap -- Snap tolerance. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--overlay='{}'\".format(overlay))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--snap={}\".format(snap))\n        return self.run_tool('intersect', args, callback) # returns 1 if error\n\n    def line_intersections(self, input1, input2, output, callback=None):\n        \"\"\"Identifies points where the features of two vector line layers intersect.\n\n        Keyword arguments:\n\n        input1 -- Input vector polyline file. \n        input2 -- Input vector polyline file. \n        output -- Output vector point file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('line_intersections', args, callback) # returns 1 if error\n\n    def lowest_position(self, inputs, output, callback=None):\n        \"\"\"Identifies the stack position of the minimum value within a raster stack on a cell-by-cell basis.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('lowest_position', args, callback) # returns 1 if error\n\n    def max_absolute_overlay(self, inputs, output, callback=None):\n        \"\"\"Evaluates the maximum absolute value for each grid cell from a stack of input rasters.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('max_absolute_overlay', args, callback) # returns 1 if error\n\n    def max_overlay(self, inputs, output, callback=None):\n        \"\"\"Evaluates the maximum value for each grid cell from a stack of input rasters.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('max_overlay', args, callback) # returns 1 if error\n\n    def merge_line_segments(self, i, output, snap=0.0, callback=None):\n        \"\"\"Merges vector line segments into larger features.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output vector file. \n        snap -- Snap tolerance. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--snap={}\".format(snap))\n        return self.run_tool('merge_line_segments', args, callback) # returns 1 if error\n\n    def min_absolute_overlay(self, inputs, output, callback=None):\n        \"\"\"Evaluates the minimum absolute value for each grid cell from a stack of input rasters.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('min_absolute_overlay', args, callback) # returns 1 if error\n\n    def min_overlay(self, inputs, output, callback=None):\n        \"\"\"Evaluates the minimum value for each grid cell from a stack of input rasters.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('min_overlay', args, callback) # returns 1 if error\n\n    def percent_equal_to(self, inputs, comparison, output, callback=None):\n        \"\"\"Calculates the percentage of a raster stack that have cell values equal to an input on a cell-by-cell basis.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        comparison -- Input comparison raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--comparison='{}'\".format(comparison))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('percent_equal_to', args, callback) # returns 1 if error\n\n    def percent_greater_than(self, inputs, comparison, output, callback=None):\n        \"\"\"Calculates the percentage of a raster stack that have cell values greather than an input on a cell-by-cell basis.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        comparison -- Input comparison raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--comparison='{}'\".format(comparison))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('percent_greater_than', args, callback) # returns 1 if error\n\n    def percent_less_than(self, inputs, comparison, output, callback=None):\n        \"\"\"Calculates the percentage of a raster stack that have cell values less than an input on a cell-by-cell basis.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        comparison -- Input comparison raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--comparison='{}'\".format(comparison))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('percent_less_than', args, callback) # returns 1 if error\n\n    def pick_from_list(self, inputs, pos_input, output, callback=None):\n        \"\"\"Outputs the value from a raster stack specified by a position raster.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        pos_input -- Input position raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--pos_input='{}'\".format(pos_input))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('pick_from_list', args, callback) # returns 1 if error\n\n    def polygonize(self, inputs, output, callback=None):\n        \"\"\"Creates a polygon layer from two or more intersecting line features contained in one or more input vector line files.\n\n        Keyword arguments:\n\n        inputs -- Input vector polyline file. \n        output -- Output vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('polygonize', args, callback) # returns 1 if error\n\n    def split_with_lines(self, i, split, output, callback=None):\n        \"\"\"Splits the lines or polygons in one layer using the lines in another layer.\n\n        Keyword arguments:\n\n        i -- Input vector line or polygon file. \n        split -- Input vector polyline file. \n        output -- Output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--split='{}'\".format(split))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('split_with_lines', args, callback) # returns 1 if error\n\n    def sum_overlay(self, inputs, output, callback=None):\n        \"\"\"Calculates the sum for each grid cell from a group of raster images.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('sum_overlay', args, callback) # returns 1 if error\n\n    def symmetrical_difference(self, i, overlay, output, snap=0.0, callback=None):\n        \"\"\"Outputs the features that occur in one of the two vector inputs but not both, i.e. no overlapping features.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        overlay -- Input overlay vector file. \n        output -- Output vector file. \n        snap -- Snap tolerance. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--overlay='{}'\".format(overlay))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--snap={}\".format(snap))\n        return self.run_tool('symmetrical_difference', args, callback) # returns 1 if error\n\n    def union(self, i, overlay, output, snap=0.0, callback=None):\n        \"\"\"Splits vector layers at their overlaps, creating a layer containing all the portions from both input and overlay layers.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        overlay -- Input overlay vector file. \n        output -- Output vector file. \n        snap -- Snap tolerance. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--overlay='{}'\".format(overlay))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--snap={}\".format(snap))\n        return self.run_tool('union', args, callback) # returns 1 if error\n\n    def weighted_overlay(self, factors, weights, output, cost=None, constraints=None, scale_max=1.0, callback=None):\n        \"\"\"Performs a weighted sum on multiple input rasters after converting each image to a common scale. The tool performs a multi-criteria evaluation (MCE).\n\n        Keyword arguments:\n\n        factors -- Input factor raster files. \n        weights -- Weight values, contained in quotes and separated by commas or semicolons. Must have the same number as factors. \n        cost -- Weight values, contained in quotes and separated by commas or semicolons. Must have the same number as factors. \n        constraints -- Input constraints raster files. \n        output -- Output raster file. \n        scale_max -- Suitability scale maximum value (common values are 1.0, 100.0, and 255.0). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--factors='{}'\".format(factors))\n        args.append(\"--weights='{}'\".format(weights))\n        if cost is not None: args.append(\"--cost='{}'\".format(cost))\n        if constraints is not None: args.append(\"--constraints='{}'\".format(constraints))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--scale_max={}\".format(scale_max))\n        return self.run_tool('weighted_overlay', args, callback) # returns 1 if error\n\n    def weighted_sum(self, inputs, weights, output, callback=None):\n        \"\"\"Performs a weighted-sum overlay on multiple input raster images.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        weights -- Weight values, contained in quotes and separated by commas or semicolons. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--weights='{}'\".format(weights))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('weighted_sum', args, callback) # returns 1 if error\n\n    ##################################\n    # GIS Analysis/Patch Shape Tools #\n    ##################################\n\n    def boundary_shape_complexity(self, i, output, callback=None):\n        \"\"\"Calculates the complexity of the boundaries of raster polygons.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('boundary_shape_complexity', args, callback) # returns 1 if error\n\n    def compactness_ratio(self, i, callback=None):\n        \"\"\"Calculates the compactness ratio (A/P), a measure of shape complexity, for vector polygons.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('compactness_ratio', args, callback) # returns 1 if error\n\n    def edge_proportion(self, i, output, output_text=False, callback=None):\n        \"\"\"Calculate the proportion of cells in a raster polygon that are edge cells.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        output_text -- flag indicating whether a text report should also be output. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if output_text: args.append(\"--output_text\")\n        return self.run_tool('edge_proportion', args, callback) # returns 1 if error\n\n    def elongation_ratio(self, i, callback=None):\n        \"\"\"Calculates the elongation ratio for vector polygons.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('elongation_ratio', args, callback) # returns 1 if error\n\n    def find_patch_or_class_edge_cells(self, i, output, callback=None):\n        \"\"\"Finds all cells located on the edge of patch or class features.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('find_patch_or_class_edge_cells', args, callback) # returns 1 if error\n\n    def hole_proportion(self, i, callback=None):\n        \"\"\"Calculates the proportion of the total area of a polygon's holes relative to the area of the polygon's hull.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('hole_proportion', args, callback) # returns 1 if error\n\n    def linearity_index(self, i, callback=None):\n        \"\"\"Calculates the linearity index for vector polygons.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('linearity_index', args, callback) # returns 1 if error\n\n    def narrowness_index(self, i, output, callback=None):\n        \"\"\"Calculates the narrowness of raster polygons.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('narrowness_index', args, callback) # returns 1 if error\n\n    def patch_orientation(self, i, callback=None):\n        \"\"\"Calculates the orientation of vector polygons.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('patch_orientation', args, callback) # returns 1 if error\n\n    def perimeter_area_ratio(self, i, callback=None):\n        \"\"\"Calculates the perimeter-area ratio of vector polygons.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('perimeter_area_ratio', args, callback) # returns 1 if error\n\n    def radius_of_gyration(self, i, output, text_output=False, callback=None):\n        \"\"\"Calculates the distance of cells from their polygon's centroid.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        text_output -- Optional text output. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if text_output: args.append(\"--text_output\")\n        return self.run_tool('radius_of_gyration', args, callback) # returns 1 if error\n\n    def related_circumscribing_circle(self, i, callback=None):\n        \"\"\"Calculates the related circumscribing circle of vector polygons.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('related_circumscribing_circle', args, callback) # returns 1 if error\n\n    def shape_complexity_index(self, i, callback=None):\n        \"\"\"Calculates overall polygon shape complexity or irregularity.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('shape_complexity_index', args, callback) # returns 1 if error\n\n    def shape_complexity_index_raster(self, i, output, callback=None):\n        \"\"\"Calculates the complexity of raster polygons or classes.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('shape_complexity_index_raster', args, callback) # returns 1 if error\n\n    ############################\n    # Geomorphometric Analysis #\n    ############################\n\n    def aspect(self, dem, output, zfactor=1.0, callback=None):\n        \"\"\"Calculates an aspect raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('aspect', args, callback) # returns 1 if error\n\n    def average_normal_vector_angular_deviation(self, dem, output, filter=11, callback=None):\n        \"\"\"Calculates the circular variance of aspect at a scale for a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filter -- Size of the filter kernel. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        return self.run_tool('average_normal_vector_angular_deviation', args, callback) # returns 1 if error\n\n    def circular_variance_of_aspect(self, dem, output, filter=11, callback=None):\n        \"\"\"Calculates the circular variance of aspect at a scale for a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filter -- Size of the filter kernel. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        return self.run_tool('circular_variance_of_aspect', args, callback) # returns 1 if error\n\n    def dev_from_mean_elev(self, dem, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Calculates deviation from mean elevation.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('dev_from_mean_elev', args, callback) # returns 1 if error\n\n    def diff_from_mean_elev(self, dem, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Calculates difference from mean elevation (equivalent to a high-pass filter).\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('diff_from_mean_elev', args, callback) # returns 1 if error\n\n    def directional_relief(self, dem, output, azimuth=0.0, max_dist=None, callback=None):\n        \"\"\"Calculates relief for cells in an input DEM for a specified direction.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        azimuth -- Wind azimuth in degrees. \n        max_dist -- Optional maximum search distance (unspecified if none; in xy units). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--azimuth={}\".format(azimuth))\n        if max_dist is not None: args.append(\"--max_dist='{}'\".format(max_dist))\n        return self.run_tool('directional_relief', args, callback) # returns 1 if error\n\n    def downslope_index(self, dem, output, drop=2.0, out_type=\"tangent\", callback=None):\n        \"\"\"Calculates the Hjerdt et al. (2004) downslope index.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        drop -- Vertical drop value (default is 2.0). \n        out_type -- Output type, options include 'tangent', 'degrees', 'radians', 'distance' (default is 'tangent'). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--drop={}\".format(drop))\n        args.append(\"--out_type={}\".format(out_type))\n        return self.run_tool('downslope_index', args, callback) # returns 1 if error\n\n    def edge_density(self, dem, output, filter=11, norm_diff=5.0, zfactor=1.0, callback=None):\n        \"\"\"Calculates the density of edges, or breaks-in-slope within DEMs.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filter -- Size of the filter kernel. \n        norm_diff -- Maximum difference in normal vectors, in degrees. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        args.append(\"--norm_diff={}\".format(norm_diff))\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('edge_density', args, callback) # returns 1 if error\n\n    def elev_above_pit(self, dem, output, callback=None):\n        \"\"\"Calculate the elevation of each grid cell above the nearest downstream pit cell or grid edge cell.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('elev_above_pit', args, callback) # returns 1 if error\n\n    def elev_percentile(self, dem, output, filterx=11, filtery=11, sig_digits=2, callback=None):\n        \"\"\"Calculates the elevation percentile raster from a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        sig_digits -- Number of significant digits. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        args.append(\"--sig_digits={}\".format(sig_digits))\n        return self.run_tool('elev_percentile', args, callback) # returns 1 if error\n\n    def elev_relative_to_min_max(self, dem, output, callback=None):\n        \"\"\"Calculates the elevation of a location relative to the minimum and maximum elevations in a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('elev_relative_to_min_max', args, callback) # returns 1 if error\n\n    def elev_relative_to_watershed_min_max(self, dem, watersheds, output, callback=None):\n        \"\"\"Calculates the elevation of a location relative to the minimum and maximum elevations in a watershed.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        watersheds -- Input raster watersheds file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--watersheds='{}'\".format(watersheds))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('elev_relative_to_watershed_min_max', args, callback) # returns 1 if error\n\n    def feature_preserving_smoothing(self, dem, output, filter=11, norm_diff=15.0, num_iter=3, max_diff=0.5, zfactor=1.0, callback=None):\n        \"\"\"Reduces short-scale variation in an input DEM using a modified Sun et al. (2007) algorithm.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filter -- Size of the filter kernel. \n        norm_diff -- Maximum difference in normal vectors, in degrees. \n        num_iter -- Number of iterations. \n        max_diff -- Maximum allowable absolute elevation change (optional). \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        args.append(\"--norm_diff={}\".format(norm_diff))\n        args.append(\"--num_iter={}\".format(num_iter))\n        args.append(\"--max_diff={}\".format(max_diff))\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('feature_preserving_smoothing', args, callback) # returns 1 if error\n\n    def fetch_analysis(self, dem, output, azimuth=0.0, hgt_inc=0.05, callback=None):\n        \"\"\"Performs an analysis of fetch or upwind distance to an obstacle.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        azimuth -- Wind azimuth in degrees in degrees. \n        hgt_inc -- Height increment value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--azimuth={}\".format(azimuth))\n        args.append(\"--hgt_inc={}\".format(hgt_inc))\n        return self.run_tool('fetch_analysis', args, callback) # returns 1 if error\n\n    def fill_missing_data(self, i, output, filter=11, weight=2.0, callback=None):\n        \"\"\"Fills NoData holes in a DEM.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filter -- Filter size (cells). \n        weight -- IDW weight value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        args.append(\"--weight={}\".format(weight))\n        return self.run_tool('fill_missing_data', args, callback) # returns 1 if error\n\n    def find_ridges(self, dem, output, line_thin=True, callback=None):\n        \"\"\"Identifies potential ridge and peak grid cells.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        line_thin -- Optional flag indicating whether post-processing line-thinning should be performed. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if line_thin: args.append(\"--line_thin\")\n        return self.run_tool('find_ridges', args, callback) # returns 1 if error\n\n    def hillshade(self, dem, output, azimuth=315.0, altitude=30.0, zfactor=1.0, callback=None):\n        \"\"\"Calculates a hillshade raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        azimuth -- Illumination source azimuth in degrees. \n        altitude -- Illumination source altitude in degrees. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--azimuth={}\".format(azimuth))\n        args.append(\"--altitude={}\".format(altitude))\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('hillshade', args, callback) # returns 1 if error\n\n    def horizon_angle(self, dem, output, azimuth=0.0, max_dist=None, callback=None):\n        \"\"\"Calculates horizon angle (maximum upwind slope) for each grid cell in an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        azimuth -- Wind azimuth in degrees. \n        max_dist -- Optional maximum search distance (unspecified if none; in xy units). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--azimuth={}\".format(azimuth))\n        if max_dist is not None: args.append(\"--max_dist='{}'\".format(max_dist))\n        return self.run_tool('horizon_angle', args, callback) # returns 1 if error\n\n    def hypsometric_analysis(self, inputs, output, watershed=None, callback=None):\n        \"\"\"Calculates a hypsometric curve for one or more DEMs.\n\n        Keyword arguments:\n\n        inputs -- Input DEM files. \n        watershed -- Input watershed files (optional). \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        if watershed is not None: args.append(\"--watershed='{}'\".format(watershed))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('hypsometric_analysis', args, callback) # returns 1 if error\n\n    def max_anisotropy_dev(self, dem, out_mag, out_scale, max_scale, min_scale=3, step=2, callback=None):\n        \"\"\"Calculates the maximum anisotropy (directionality) in elevation deviation over a range of spatial scales.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        out_mag -- Output raster DEVmax magnitude file. \n        out_scale -- Output raster DEVmax scale file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        max_scale -- Maximum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--out_mag='{}'\".format(out_mag))\n        args.append(\"--out_scale='{}'\".format(out_scale))\n        args.append(\"--min_scale={}\".format(min_scale))\n        args.append(\"--max_scale='{}'\".format(max_scale))\n        args.append(\"--step={}\".format(step))\n        return self.run_tool('max_anisotropy_dev', args, callback) # returns 1 if error\n\n    def max_anisotropy_dev_signature(self, dem, points, output, max_scale, min_scale=1, step=1, callback=None):\n        \"\"\"Calculates the anisotropy in deviation from mean for points over a range of spatial scales.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        points -- Input vector points file. \n        output -- Output HTML file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        max_scale -- Maximum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--points='{}'\".format(points))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--min_scale={}\".format(min_scale))\n        args.append(\"--max_scale='{}'\".format(max_scale))\n        args.append(\"--step={}\".format(step))\n        return self.run_tool('max_anisotropy_dev_signature', args, callback) # returns 1 if error\n\n    def max_branch_length(self, dem, output, log=False, callback=None):\n        \"\"\"Lindsay and Seibert's (2013) branch length index is used to map drainage divides or ridge lines.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        log -- Optional flag to request the output be log-transformed. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        return self.run_tool('max_branch_length', args, callback) # returns 1 if error\n\n    def max_difference_from_mean(self, dem, out_mag, out_scale, min_scale, max_scale, step=1, callback=None):\n        \"\"\"Calculates the maximum difference from mean elevation over a range of spatial scales.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        out_mag -- Output raster DIFFmax magnitude file. \n        out_scale -- Output raster DIFFmax scale file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        max_scale -- Maximum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--out_mag='{}'\".format(out_mag))\n        args.append(\"--out_scale='{}'\".format(out_scale))\n        args.append(\"--min_scale='{}'\".format(min_scale))\n        args.append(\"--max_scale='{}'\".format(max_scale))\n        args.append(\"--step={}\".format(step))\n        return self.run_tool('max_difference_from_mean', args, callback) # returns 1 if error\n\n    def max_downslope_elev_change(self, dem, output, callback=None):\n        \"\"\"Calculates the maximum downslope change in elevation between a grid cell and its eight downslope neighbors.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('max_downslope_elev_change', args, callback) # returns 1 if error\n\n    def max_elev_dev_signature(self, dem, points, output, min_scale, max_scale, step=10, callback=None):\n        \"\"\"Calculates the maximum elevation deviation over a range of spatial scales and for a set of points.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        points -- Input vector points file. \n        output -- Output HTML file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        max_scale -- Maximum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--points='{}'\".format(points))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--min_scale='{}'\".format(min_scale))\n        args.append(\"--max_scale='{}'\".format(max_scale))\n        args.append(\"--step={}\".format(step))\n        return self.run_tool('max_elev_dev_signature', args, callback) # returns 1 if error\n\n    def max_elevation_deviation(self, dem, out_mag, out_scale, min_scale, max_scale, step=1, callback=None):\n        \"\"\"Calculates the maximum elevation deviation over a range of spatial scales.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        out_mag -- Output raster DEVmax magnitude file. \n        out_scale -- Output raster DEVmax scale file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        max_scale -- Maximum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--out_mag='{}'\".format(out_mag))\n        args.append(\"--out_scale='{}'\".format(out_scale))\n        args.append(\"--min_scale='{}'\".format(min_scale))\n        args.append(\"--max_scale='{}'\".format(max_scale))\n        args.append(\"--step={}\".format(step))\n        return self.run_tool('max_elevation_deviation', args, callback) # returns 1 if error\n\n    def min_downslope_elev_change(self, dem, output, callback=None):\n        \"\"\"Calculates the minimum downslope change in elevation between a grid cell and its eight downslope neighbors.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('min_downslope_elev_change', args, callback) # returns 1 if error\n\n    def multiscale_elevation_percentile(self, dem, out_mag, out_scale, sig_digits=3, min_scale=4, step=1, num_steps=10, step_nonlinearity=1.0, callback=None):\n        \"\"\"Calculates surface roughness over a range of spatial scales.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        out_mag -- Output raster roughness magnitude file. \n        out_scale -- Output raster roughness scale file. \n        sig_digits -- Number of significant digits. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        num_steps -- Number of steps. \n        step_nonlinearity -- Step nonlinearity factor (1.0-2.0 is typical). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--out_mag='{}'\".format(out_mag))\n        args.append(\"--out_scale='{}'\".format(out_scale))\n        args.append(\"--sig_digits={}\".format(sig_digits))\n        args.append(\"--min_scale={}\".format(min_scale))\n        args.append(\"--step={}\".format(step))\n        args.append(\"--num_steps={}\".format(num_steps))\n        args.append(\"--step_nonlinearity={}\".format(step_nonlinearity))\n        return self.run_tool('multiscale_elevation_percentile', args, callback) # returns 1 if error\n\n    def multiscale_roughness(self, dem, out_mag, out_scale, max_scale, min_scale=1, step=1, callback=None):\n        \"\"\"Calculates surface roughness over a range of spatial scales.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        out_mag -- Output raster roughness magnitude file. \n        out_scale -- Output raster roughness scale file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        max_scale -- Maximum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--out_mag='{}'\".format(out_mag))\n        args.append(\"--out_scale='{}'\".format(out_scale))\n        args.append(\"--min_scale={}\".format(min_scale))\n        args.append(\"--max_scale='{}'\".format(max_scale))\n        args.append(\"--step={}\".format(step))\n        return self.run_tool('multiscale_roughness', args, callback) # returns 1 if error\n\n    def multiscale_roughness_signature(self, dem, points, output, max_scale, min_scale=1, step=1, callback=None):\n        \"\"\"Calculates the surface roughness for points over a range of spatial scales.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        points -- Input vector points file. \n        output -- Output HTML file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        max_scale -- Maximum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--points='{}'\".format(points))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--min_scale={}\".format(min_scale))\n        args.append(\"--max_scale='{}'\".format(max_scale))\n        args.append(\"--step={}\".format(step))\n        return self.run_tool('multiscale_roughness_signature', args, callback) # returns 1 if error\n\n    def multiscale_std_dev_normals(self, dem, out_mag, out_scale, min_scale=1, step=1, num_steps=10, step_nonlinearity=1.0, callback=None):\n        \"\"\"Calculates surface roughness over a range of spatial scales.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        out_mag -- Output raster roughness magnitude file. \n        out_scale -- Output raster roughness scale file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        num_steps -- Number of steps. \n        step_nonlinearity -- Step nonlinearity factor (1.0-2.0 is typical). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--out_mag='{}'\".format(out_mag))\n        args.append(\"--out_scale='{}'\".format(out_scale))\n        args.append(\"--min_scale={}\".format(min_scale))\n        args.append(\"--step={}\".format(step))\n        args.append(\"--num_steps={}\".format(num_steps))\n        args.append(\"--step_nonlinearity={}\".format(step_nonlinearity))\n        return self.run_tool('multiscale_std_dev_normals', args, callback) # returns 1 if error\n\n    def multiscale_std_dev_normals_signature(self, dem, points, output, min_scale=1, step=1, num_steps=10, step_nonlinearity=1.0, callback=None):\n        \"\"\"Calculates the surface roughness for points over a range of spatial scales.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        points -- Input vector points file. \n        output -- Output HTML file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        num_steps -- Number of steps. \n        step_nonlinearity -- Step nonlinearity factor (1.0-2.0 is typical). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--points='{}'\".format(points))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--min_scale={}\".format(min_scale))\n        args.append(\"--step={}\".format(step))\n        args.append(\"--num_steps={}\".format(num_steps))\n        args.append(\"--step_nonlinearity={}\".format(step_nonlinearity))\n        return self.run_tool('multiscale_std_dev_normals_signature', args, callback) # returns 1 if error\n\n    def multiscale_topographic_position_image(self, local, meso, broad, output, lightness=1.2, callback=None):\n        \"\"\"Creates a multiscale topographic position image from three DEVmax rasters of differing spatial scale ranges.\n\n        Keyword arguments:\n\n        local -- Input local-scale topographic position (DEVmax) raster file. \n        meso -- Input meso-scale topographic position (DEVmax) raster file. \n        broad -- Input broad-scale topographic position (DEVmax) raster file. \n        output -- Output raster file. \n        lightness -- Image lightness value (default is 1.2). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--local='{}'\".format(local))\n        args.append(\"--meso='{}'\".format(meso))\n        args.append(\"--broad='{}'\".format(broad))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--lightness={}\".format(lightness))\n        return self.run_tool('multiscale_topographic_position_image', args, callback) # returns 1 if error\n\n    def num_downslope_neighbours(self, dem, output, callback=None):\n        \"\"\"Calculates the number of downslope neighbours to each grid cell in a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('num_downslope_neighbours', args, callback) # returns 1 if error\n\n    def num_upslope_neighbours(self, dem, output, callback=None):\n        \"\"\"Calculates the number of upslope neighbours to each grid cell in a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('num_upslope_neighbours', args, callback) # returns 1 if error\n\n    def pennock_landform_class(self, dem, output, slope=3.0, prof=0.1, plan=0.0, zfactor=1.0, callback=None):\n        \"\"\"Classifies hillslope zones based on slope, profile curvature, and plan curvature.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        slope -- Slope threshold value, in degrees (default is 3.0). \n        prof -- Profile curvature threshold value (default is 0.1). \n        plan -- Plan curvature threshold value (default is 0.0). \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--slope={}\".format(slope))\n        args.append(\"--prof={}\".format(prof))\n        args.append(\"--plan={}\".format(plan))\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('pennock_landform_class', args, callback) # returns 1 if error\n\n    def percent_elev_range(self, dem, output, filterx=3, filtery=3, callback=None):\n        \"\"\"Calculates percent of elevation range from a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('percent_elev_range', args, callback) # returns 1 if error\n\n    def plan_curvature(self, dem, output, zfactor=1.0, callback=None):\n        \"\"\"Calculates a plan (contour) curvature raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('plan_curvature', args, callback) # returns 1 if error\n\n    def profile(self, lines, surface, output, callback=None):\n        \"\"\"Plots profiles from digital surface models.\n\n        Keyword arguments:\n\n        lines -- Input vector line file. \n        surface -- Input raster surface file. \n        output -- Output HTML file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--lines='{}'\".format(lines))\n        args.append(\"--surface='{}'\".format(surface))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('profile', args, callback) # returns 1 if error\n\n    def profile_curvature(self, dem, output, zfactor=1.0, callback=None):\n        \"\"\"Calculates a profile curvature raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('profile_curvature', args, callback) # returns 1 if error\n\n    def relative_aspect(self, dem, output, azimuth=0.0, zfactor=1.0, callback=None):\n        \"\"\"Calculates relative aspect (relative to a user-specified direction) from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        azimuth -- Illumination source azimuth. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--azimuth={}\".format(azimuth))\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('relative_aspect', args, callback) # returns 1 if error\n\n    def relative_topographic_position(self, dem, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Calculates the relative topographic position index from a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('relative_topographic_position', args, callback) # returns 1 if error\n\n    def remove_off_terrain_objects(self, dem, output, filter=11, slope=15.0, callback=None):\n        \"\"\"Removes off-terrain objects from a raster digital elevation model (DEM).\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filter -- Filter size (cells). \n        slope -- Slope threshold value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        args.append(\"--slope={}\".format(slope))\n        return self.run_tool('remove_off_terrain_objects', args, callback) # returns 1 if error\n\n    def ruggedness_index(self, dem, output, zfactor=1.0, callback=None):\n        \"\"\"Calculates the Riley et al.'s (1999) terrain ruggedness index from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('ruggedness_index', args, callback) # returns 1 if error\n\n    def sediment_transport_index(self, sca, slope, output, sca_exponent=0.4, slope_exponent=1.3, callback=None):\n        \"\"\"Calculates the sediment transport index.\n\n        Keyword arguments:\n\n        sca -- Input raster specific contributing area (SCA) file. \n        slope -- Input raster slope file. \n        output -- Output raster file. \n        sca_exponent -- SCA exponent value. \n        slope_exponent -- Slope exponent value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--sca='{}'\".format(sca))\n        args.append(\"--slope='{}'\".format(slope))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--sca_exponent={}\".format(sca_exponent))\n        args.append(\"--slope_exponent={}\".format(slope_exponent))\n        return self.run_tool('sediment_transport_index', args, callback) # returns 1 if error\n\n    def slope(self, dem, output, zfactor=1.0, callback=None):\n        \"\"\"Calculates a slope raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('slope', args, callback) # returns 1 if error\n\n    def slope_vs_elevation_plot(self, inputs, output, watershed=None, callback=None):\n        \"\"\"Creates a slope vs. elevation plot for one or more DEMs.\n\n        Keyword arguments:\n\n        inputs -- Input DEM files. \n        watershed -- Input watershed files (optional). \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        if watershed is not None: args.append(\"--watershed='{}'\".format(watershed))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('slope_vs_elevation_plot', args, callback) # returns 1 if error\n\n    def spherical_std_dev_of_normals(self, dem, output, filter=11, callback=None):\n        \"\"\"Calculates the spherical standard deviation of surface normals for a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filter -- Size of the filter kernel. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        return self.run_tool('spherical_std_dev_of_normals', args, callback) # returns 1 if error\n\n    def standard_deviation_of_slope(self, i, output, zfactor=1.0, filterx=11, filtery=11, callback=None):\n        \"\"\"Calculates the standard deviation of slope from an input DEM.\n\n        Keyword arguments:\n\n        i -- Input raster DEM file. \n        output -- Output raster DEM file. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--zfactor={}\".format(zfactor))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('standard_deviation_of_slope', args, callback) # returns 1 if error\n\n    def stream_power_index(self, sca, slope, output, exponent=1.0, callback=None):\n        \"\"\"Calculates the relative stream power index.\n\n        Keyword arguments:\n\n        sca -- Input raster specific contributing area (SCA) file. \n        slope -- Input raster slope file. \n        output -- Output raster file. \n        exponent -- SCA exponent value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--sca='{}'\".format(sca))\n        args.append(\"--slope='{}'\".format(slope))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--exponent={}\".format(exponent))\n        return self.run_tool('stream_power_index', args, callback) # returns 1 if error\n\n    def surface_area_ratio(self, dem, output, callback=None):\n        \"\"\"Calculates a the surface area ratio of each grid cell in an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('surface_area_ratio', args, callback) # returns 1 if error\n\n    def tangential_curvature(self, dem, output, zfactor=1.0, callback=None):\n        \"\"\"Calculates a tangential curvature raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('tangential_curvature', args, callback) # returns 1 if error\n\n    def total_curvature(self, dem, output, zfactor=1.0, callback=None):\n        \"\"\"Calculates a total curvature raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('total_curvature', args, callback) # returns 1 if error\n\n    def viewshed(self, dem, stations, output, height=2.0, callback=None):\n        \"\"\"Identifies the viewshed for a point or set of points.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        stations -- Input viewing station vector file. \n        output -- Output raster file. \n        height -- Viewing station height, in z units. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--stations='{}'\".format(stations))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--height={}\".format(height))\n        return self.run_tool('viewshed', args, callback) # returns 1 if error\n\n    def visibility_index(self, dem, output, height=2.0, res_factor=2, callback=None):\n        \"\"\"Estimates the relative visibility of sites in a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        height -- Viewing station height, in z units. \n        res_factor -- The resolution factor determines the density of measured viewsheds. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--height={}\".format(height))\n        args.append(\"--res_factor={}\".format(res_factor))\n        return self.run_tool('visibility_index', args, callback) # returns 1 if error\n\n    def wetness_index(self, sca, slope, output, callback=None):\n        \"\"\"Calculates the topographic wetness index, Ln(A / tan(slope)).\n\n        Keyword arguments:\n\n        sca -- Input raster specific contributing area (SCA) file. \n        slope -- Input raster slope file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--sca='{}'\".format(sca))\n        args.append(\"--slope='{}'\".format(slope))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('wetness_index', args, callback) # returns 1 if error\n\n    #########################\n    # Hydrological Analysis #\n    #########################\n\n    def average_flowpath_slope(self, dem, output, callback=None):\n        \"\"\"Measures the average slope gradient from each grid cell to all upslope divide cells.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('average_flowpath_slope', args, callback) # returns 1 if error\n\n    def average_upslope_flowpath_length(self, dem, output, callback=None):\n        \"\"\"Measures the average length of all upslope flowpaths draining each grid cell.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('average_upslope_flowpath_length', args, callback) # returns 1 if error\n\n    def basins(self, d8_pntr, output, esri_pntr=False, callback=None):\n        \"\"\"Identifies drainage basins that drain to the DEM edge.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('basins', args, callback) # returns 1 if error\n\n    def breach_depressions(self, dem, output, max_depth=None, max_length=None, flat_increment=None, fill_pits=False, callback=None):\n        \"\"\"Breaches all of the depressions in a DEM using Lindsay's (2016) algorithm. This should be preferred over depression filling in most cases.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        max_depth -- Optional maximum breach depth (default is Inf). \n        max_length -- Optional maximum breach channel length (in grid cells; default is Inf). \n        flat_increment -- Optional elevation increment applied to flat areas. \n        fill_pits -- Optional flag indicating whether to fill single-cell pits. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if max_depth is not None: args.append(\"--max_depth='{}'\".format(max_depth))\n        if max_length is not None: args.append(\"--max_length='{}'\".format(max_length))\n        if flat_increment is not None: args.append(\"--flat_increment='{}'\".format(flat_increment))\n        if fill_pits: args.append(\"--fill_pits\")\n        return self.run_tool('breach_depressions', args, callback) # returns 1 if error\n\n    def breach_depressions_least_cost(self, dem, output, dist, max_cost=None, min_dist=True, flat_increment=None, fill=True, callback=None):\n        \"\"\"Breaches the depressions in a DEM using a least-cost pathway method.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        dist -- . \n        max_cost -- Optional maximum breach cost (default is Inf). \n        min_dist -- Optional flag indicating whether to minimize breach distances. \n        flat_increment -- Optional elevation increment applied to flat areas. \n        fill -- Optional flag indicating whether to fill any remaining unbreached depressions. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--dist='{}'\".format(dist))\n        if max_cost is not None: args.append(\"--max_cost='{}'\".format(max_cost))\n        if min_dist: args.append(\"--min_dist\")\n        if flat_increment is not None: args.append(\"--flat_increment='{}'\".format(flat_increment))\n        if fill: args.append(\"--fill\")\n        return self.run_tool('breach_depressions_least_cost', args, callback) # returns 1 if error\n\n    def breach_single_cell_pits(self, dem, output, callback=None):\n        \"\"\"Removes single-cell pits from an input DEM by breaching.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('breach_single_cell_pits', args, callback) # returns 1 if error\n\n    def burn_streams_at_roads(self, dem, streams, roads, output, width=None, callback=None):\n        \"\"\"Burns-in streams at the sites of road embankments.\n\n        Keyword arguments:\n\n        dem -- Input raster digital elevation model (DEM) file. \n        streams -- Input vector streams file. \n        roads -- Input vector roads file. \n        output -- Output raster file. \n        width -- Maximum road embankment width, in map units. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--roads='{}'\".format(roads))\n        args.append(\"--output='{}'\".format(output))\n        if width is not None: args.append(\"--width='{}'\".format(width))\n        return self.run_tool('burn_streams_at_roads', args, callback) # returns 1 if error\n\n    def d8_flow_accumulation(self, i, output, out_type=\"cells\", log=False, clip=False, pntr=False, esri_pntr=False, callback=None):\n        \"\"\"Calculates a D8 flow accumulation raster from an input DEM or flow pointer.\n\n        Keyword arguments:\n\n        i -- Input raster DEM or D8 pointer file. \n        output -- Output raster file. \n        out_type -- Output type; one of 'cells' (default), 'catchment area', and 'specific contributing area'. \n        log -- Optional flag to request the output be log-transformed. \n        clip -- Optional flag to request clipping the display max by 1%. \n        pntr -- Is the input raster a D8 flow pointer rather than a DEM?. \n        esri_pntr -- Input  D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--out_type={}\".format(out_type))\n        if log: args.append(\"--log\")\n        if clip: args.append(\"--clip\")\n        if pntr: args.append(\"--pntr\")\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('d8_flow_accumulation', args, callback) # returns 1 if error\n\n    def d8_mass_flux(self, dem, loading, efficiency, absorption, output, callback=None):\n        \"\"\"Performs a D8 mass flux calculation.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        loading -- Input loading raster file. \n        efficiency -- Input efficiency raster file. \n        absorption -- Input absorption raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--loading='{}'\".format(loading))\n        args.append(\"--efficiency='{}'\".format(efficiency))\n        args.append(\"--absorption='{}'\".format(absorption))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('d8_mass_flux', args, callback) # returns 1 if error\n\n    def d8_pointer(self, dem, output, esri_pntr=False, callback=None):\n        \"\"\"Calculates a D8 flow pointer raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('d8_pointer', args, callback) # returns 1 if error\n\n    def d_inf_flow_accumulation(self, i, output, out_type=\"Specific Contributing Area\", threshold=None, log=False, clip=False, pntr=False, callback=None):\n        \"\"\"Calculates a D-infinity flow accumulation raster from an input DEM.\n\n        Keyword arguments:\n\n        i -- Input raster DEM or D-infinity pointer file. \n        output -- Output raster file. \n        out_type -- Output type; one of 'cells', 'sca' (default), and 'ca'. \n        threshold -- Optional convergence threshold parameter, in grid cells; default is inifinity. \n        log -- Optional flag to request the output be log-transformed. \n        clip -- Optional flag to request clipping the display max by 1%. \n        pntr -- Is the input raster a D8 flow pointer rather than a DEM?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--out_type={}\".format(out_type))\n        if threshold is not None: args.append(\"--threshold='{}'\".format(threshold))\n        if log: args.append(\"--log\")\n        if clip: args.append(\"--clip\")\n        if pntr: args.append(\"--pntr\")\n        return self.run_tool('d_inf_flow_accumulation', args, callback) # returns 1 if error\n\n    def d_inf_mass_flux(self, dem, loading, efficiency, absorption, output, callback=None):\n        \"\"\"Performs a D-infinity mass flux calculation.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        loading -- Input loading raster file. \n        efficiency -- Input efficiency raster file. \n        absorption -- Input absorption raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--loading='{}'\".format(loading))\n        args.append(\"--efficiency='{}'\".format(efficiency))\n        args.append(\"--absorption='{}'\".format(absorption))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('d_inf_mass_flux', args, callback) # returns 1 if error\n\n    def d_inf_pointer(self, dem, output, callback=None):\n        \"\"\"Calculates a D-infinity flow pointer (flow direction) raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('d_inf_pointer', args, callback) # returns 1 if error\n\n    def depth_in_sink(self, dem, output, zero_background=False, callback=None):\n        \"\"\"Measures the depth of sinks (depressions) in a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        zero_background -- Flag indicating whether the background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('depth_in_sink', args, callback) # returns 1 if error\n\n    def downslope_distance_to_stream(self, dem, streams, output, callback=None):\n        \"\"\"Measures distance to the nearest downslope stream cell.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('downslope_distance_to_stream', args, callback) # returns 1 if error\n\n    def downslope_flowpath_length(self, d8_pntr, output, watersheds=None, weights=None, esri_pntr=False, callback=None):\n        \"\"\"Calculates the downslope flowpath length from each cell to basin outlet.\n\n        Keyword arguments:\n\n        d8_pntr -- Input D8 pointer raster file. \n        watersheds -- Optional input watershed raster file. \n        weights -- Optional input weights raster file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        if watersheds is not None: args.append(\"--watersheds='{}'\".format(watersheds))\n        if weights is not None: args.append(\"--weights='{}'\".format(weights))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('downslope_flowpath_length', args, callback) # returns 1 if error\n\n    def elevation_above_stream(self, dem, streams, output, callback=None):\n        \"\"\"Calculates the elevation of cells above the nearest downslope stream cell.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('elevation_above_stream', args, callback) # returns 1 if error\n\n    def elevation_above_stream_euclidean(self, dem, streams, output, callback=None):\n        \"\"\"Calculates the elevation of cells above the nearest (Euclidean distance) stream cell.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('elevation_above_stream_euclidean', args, callback) # returns 1 if error\n\n    def fd8_flow_accumulation(self, dem, output, out_type=\"specific contributing area\", exponent=1.1, threshold=None, log=False, clip=False, callback=None):\n        \"\"\"Calculates an FD8 flow accumulation raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        out_type -- Output type; one of 'cells', 'specific contributing area' (default), and 'catchment area'. \n        exponent -- Optional exponent parameter; default is 1.1. \n        threshold -- Optional convergence threshold parameter, in grid cells; default is inifinity. \n        log -- Optional flag to request the output be log-transformed. \n        clip -- Optional flag to request clipping the display max by 1%. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--out_type={}\".format(out_type))\n        args.append(\"--exponent={}\".format(exponent))\n        if threshold is not None: args.append(\"--threshold='{}'\".format(threshold))\n        if log: args.append(\"--log\")\n        if clip: args.append(\"--clip\")\n        return self.run_tool('fd8_flow_accumulation', args, callback) # returns 1 if error\n\n    def fd8_pointer(self, dem, output, callback=None):\n        \"\"\"Calculates an FD8 flow pointer raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('fd8_pointer', args, callback) # returns 1 if error\n\n    def fill_burn(self, dem, streams, output, callback=None):\n        \"\"\"Burns streams into a DEM using the FillBurn (Saunders, 1999) method.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        streams -- Input vector streams file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('fill_burn', args, callback) # returns 1 if error\n\n    def fill_depressions(self, dem, output, fix_flats=True, flat_increment=None, max_depth=None, callback=None):\n        \"\"\"Fills all of the depressions in a DEM. Depression breaching should be preferred in most cases.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        fix_flats -- Optional flag indicating whether flat areas should have a small gradient applied. \n        flat_increment -- Optional elevation increment applied to flat areas. \n        max_depth -- Optional maximum depression depth to fill. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if fix_flats: args.append(\"--fix_flats\")\n        if flat_increment is not None: args.append(\"--flat_increment='{}'\".format(flat_increment))\n        if max_depth is not None: args.append(\"--max_depth='{}'\".format(max_depth))\n        return self.run_tool('fill_depressions', args, callback) # returns 1 if error\n\n    def fill_depressions_planchon_and_darboux(self, dem, output, fix_flats=True, flat_increment=None, callback=None):\n        \"\"\"Fills all of the depressions in a DEM using the Planchon and Darboux (2002) method.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        fix_flats -- Optional flag indicating whether flat areas should have a small gradient applied. \n        flat_increment -- Optional elevation increment applied to flat areas. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if fix_flats: args.append(\"--fix_flats\")\n        if flat_increment is not None: args.append(\"--flat_increment='{}'\".format(flat_increment))\n        return self.run_tool('fill_depressions_planchon_and_darboux', args, callback) # returns 1 if error\n\n    def fill_depressions_wang_and_liu(self, dem, output, fix_flats=True, flat_increment=None, callback=None):\n        \"\"\"Fills all of the depressions in a DEM using the Wang and Liu (2006) method. Depression breaching should be preferred in most cases.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        fix_flats -- Optional flag indicating whether flat areas should have a small gradient applied. \n        flat_increment -- Optional elevation increment applied to flat areas. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if fix_flats: args.append(\"--fix_flats\")\n        if flat_increment is not None: args.append(\"--flat_increment='{}'\".format(flat_increment))\n        return self.run_tool('fill_depressions_wang_and_liu', args, callback) # returns 1 if error\n\n    def fill_single_cell_pits(self, dem, output, callback=None):\n        \"\"\"Raises pit cells to the elevation of their lowest neighbour.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('fill_single_cell_pits', args, callback) # returns 1 if error\n\n    def find_no_flow_cells(self, dem, output, callback=None):\n        \"\"\"Finds grid cells with no downslope neighbours.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('find_no_flow_cells', args, callback) # returns 1 if error\n\n    def find_parallel_flow(self, d8_pntr, streams, output, callback=None):\n        \"\"\"Finds areas of parallel flow in D8 flow direction rasters.\n\n        Keyword arguments:\n\n        d8_pntr -- Input D8 pointer raster file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('find_parallel_flow', args, callback) # returns 1 if error\n\n    def flatten_lakes(self, dem, lakes, output, callback=None):\n        \"\"\"Flattens lake polygons in a raster DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        lakes -- Input lakes vector polygons file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--lakes='{}'\".format(lakes))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('flatten_lakes', args, callback) # returns 1 if error\n\n    def flood_order(self, dem, output, callback=None):\n        \"\"\"Assigns each DEM grid cell its order in the sequence of inundations that are encountered during a search starting from the edges, moving inward at increasing elevations.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('flood_order', args, callback) # returns 1 if error\n\n    def flow_accumulation_full_workflow(self, dem, out_dem, out_pntr, out_accum, out_type=\"Specific Contributing Area\", log=False, clip=False, esri_pntr=False, callback=None):\n        \"\"\"Resolves all of the depressions in a DEM, outputting a breached DEM, an aspect-aligned non-divergent flow pointer, and a flow accumulation raster.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        out_dem -- Output raster DEM file. \n        out_pntr -- Output raster flow pointer file. \n        out_accum -- Output raster flow accumulation file. \n        out_type -- Output type; one of 'cells', 'sca' (default), and 'ca'. \n        log -- Optional flag to request the output be log-transformed. \n        clip -- Optional flag to request clipping the display max by 1%. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--out_dem='{}'\".format(out_dem))\n        args.append(\"--out_pntr='{}'\".format(out_pntr))\n        args.append(\"--out_accum='{}'\".format(out_accum))\n        args.append(\"--out_type={}\".format(out_type))\n        if log: args.append(\"--log\")\n        if clip: args.append(\"--clip\")\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('flow_accumulation_full_workflow', args, callback) # returns 1 if error\n\n    def flow_length_diff(self, d8_pntr, output, esri_pntr=False, callback=None):\n        \"\"\"Calculates the local maximum absolute difference in downslope flowpath length, useful in mapping drainage divides and ridges.\n\n        Keyword arguments:\n\n        d8_pntr -- Input D8 pointer raster file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('flow_length_diff', args, callback) # returns 1 if error\n\n    def hillslopes(self, d8_pntr, streams, output, esri_pntr=False, callback=None):\n        \"\"\"Identifies the individual hillslopes draining to each link in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('hillslopes', args, callback) # returns 1 if error\n\n    def impoundment_size_index(self, dem, output, damlength, out_type=\"depth\", callback=None):\n        \"\"\"Calculates the impoundment size resulting from damming a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output file. \n        out_type -- Output type; one of 'depth' (default), 'volume', and 'area'. \n        damlength -- Maximum length of the dam. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--out_type={}\".format(out_type))\n        args.append(\"--damlength='{}'\".format(damlength))\n        return self.run_tool('impoundment_size_index', args, callback) # returns 1 if error\n\n    def insert_dams(self, dem, dam_pts, output, damlength, callback=None):\n        \"\"\"Calculates the impoundment size resulting from damming a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        dam_pts -- Input vector dam points file. \n        output -- Output file. \n        damlength -- Maximum length of the dam. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--dam_pts='{}'\".format(dam_pts))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--damlength='{}'\".format(damlength))\n        return self.run_tool('insert_dams', args, callback) # returns 1 if error\n\n    def isobasins(self, dem, output, size, callback=None):\n        \"\"\"Divides a landscape into nearly equal sized drainage basins (i.e. watersheds).\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        size -- Target basin size, in grid cells. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--size='{}'\".format(size))\n        return self.run_tool('isobasins', args, callback) # returns 1 if error\n\n    def jenson_snap_pour_points(self, pour_pts, streams, output, snap_dist, callback=None):\n        \"\"\"Moves outlet points used to specify points of interest in a watershedding operation to the nearest stream cell.\n\n        Keyword arguments:\n\n        pour_pts -- Input vector pour points (outlet) file. \n        streams -- Input raster streams file. \n        output -- Output vector file. \n        snap_dist -- Maximum snap distance in map units. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--pour_pts='{}'\".format(pour_pts))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--snap_dist='{}'\".format(snap_dist))\n        return self.run_tool('jenson_snap_pour_points', args, callback) # returns 1 if error\n\n    def longest_flowpath(self, dem, basins, output, callback=None):\n        \"\"\"Delineates the longest flowpaths for a group of subbasins or watersheds.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        basins -- Input raster basins file. \n        output -- Output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--basins='{}'\".format(basins))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('longest_flowpath', args, callback) # returns 1 if error\n\n    def max_upslope_flowpath_length(self, dem, output, callback=None):\n        \"\"\"Measures the maximum length of all upslope flowpaths draining each grid cell.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('max_upslope_flowpath_length', args, callback) # returns 1 if error\n\n    def md_inf_flow_accumulation(self, dem, output, out_type=\"specific contributing area\", exponent=1.1, threshold=None, log=False, clip=False, callback=None):\n        \"\"\"Calculates an FD8 flow accumulation raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        out_type -- Output type; one of 'cells', 'specific contributing area' (default), and 'catchment area'. \n        exponent -- Optional exponent parameter; default is 1.1. \n        threshold -- Optional convergence threshold parameter, in grid cells; default is inifinity. \n        log -- Optional flag to request the output be log-transformed. \n        clip -- Optional flag to request clipping the display max by 1%. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--out_type={}\".format(out_type))\n        args.append(\"--exponent={}\".format(exponent))\n        if threshold is not None: args.append(\"--threshold='{}'\".format(threshold))\n        if log: args.append(\"--log\")\n        if clip: args.append(\"--clip\")\n        return self.run_tool('md_inf_flow_accumulation', args, callback) # returns 1 if error\n\n    def num_inflowing_neighbours(self, dem, output, callback=None):\n        \"\"\"Computes the number of inflowing neighbours to each cell in an input DEM based on the D8 algorithm.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('num_inflowing_neighbours', args, callback) # returns 1 if error\n\n    def raise_walls(self, i, dem, output, breach=None, height=100.0, callback=None):\n        \"\"\"Raises walls in a DEM along a line or around a polygon, e.g. a watershed.\n\n        Keyword arguments:\n\n        i -- Input vector lines or polygons file. \n        breach -- Optional input vector breach lines. \n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        height -- Wall height. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if breach is not None: args.append(\"--breach='{}'\".format(breach))\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--height={}\".format(height))\n        return self.run_tool('raise_walls', args, callback) # returns 1 if error\n\n    def rho8_pointer(self, dem, output, esri_pntr=False, callback=None):\n        \"\"\"Calculates a stochastic Rho8 flow pointer raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('rho8_pointer', args, callback) # returns 1 if error\n\n    def sink(self, i, output, zero_background=False, callback=None):\n        \"\"\"Identifies the depressions in a DEM, giving each feature a unique identifier.\n\n        Keyword arguments:\n\n        i -- Input raster DEM file. \n        output -- Output raster file. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('sink', args, callback) # returns 1 if error\n\n    def snap_pour_points(self, pour_pts, flow_accum, output, snap_dist, callback=None):\n        \"\"\"Moves outlet points used to specify points of interest in a watershedding operation to the cell with the highest flow accumulation in its neighbourhood.\n\n        Keyword arguments:\n\n        pour_pts -- Input vector pour points (outlet) file. \n        flow_accum -- Input raster D8 flow accumulation file. \n        output -- Output vector file. \n        snap_dist -- Maximum snap distance in map units. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--pour_pts='{}'\".format(pour_pts))\n        args.append(\"--flow_accum='{}'\".format(flow_accum))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--snap_dist='{}'\".format(snap_dist))\n        return self.run_tool('snap_pour_points', args, callback) # returns 1 if error\n\n    def stochastic_depression_analysis(self, dem, output, rmse, range, iterations=100, callback=None):\n        \"\"\"Preforms a stochastic analysis of depressions within a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output file. \n        rmse -- The DEM's root-mean-square-error (RMSE), in z units. This determines error magnitude. \n        range -- The error field's correlation length, in xy-units. \n        iterations -- The number of iterations. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--rmse='{}'\".format(rmse))\n        args.append(\"--range='{}'\".format(range))\n        args.append(\"--iterations={}\".format(iterations))\n        return self.run_tool('stochastic_depression_analysis', args, callback) # returns 1 if error\n\n    def strahler_order_basins(self, d8_pntr, streams, output, esri_pntr=False, callback=None):\n        \"\"\"Identifies Strahler-order basins from an input stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('strahler_order_basins', args, callback) # returns 1 if error\n\n    def subbasins(self, d8_pntr, streams, output, esri_pntr=False, callback=None):\n        \"\"\"Identifies the catchments, or sub-basin, draining to each link in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input D8 pointer raster file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('subbasins', args, callback) # returns 1 if error\n\n    def trace_downslope_flowpaths(self, seed_pts, d8_pntr, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Traces downslope flowpaths from one or more target sites (i.e. seed points).\n\n        Keyword arguments:\n\n        seed_pts -- Input vector seed points file. \n        d8_pntr -- Input D8 pointer raster file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--seed_pts='{}'\".format(seed_pts))\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('trace_downslope_flowpaths', args, callback) # returns 1 if error\n\n    def unnest_basins(self, d8_pntr, pour_pts, output, esri_pntr=False, callback=None):\n        \"\"\"Extract whole watersheds for a set of outlet points.\n\n        Keyword arguments:\n\n        d8_pntr -- Input D8 pointer raster file. \n        pour_pts -- Input vector pour points (outlet) file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--pour_pts='{}'\".format(pour_pts))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('unnest_basins', args, callback) # returns 1 if error\n\n    def upslope_depression_storage(self, dem, output, callback=None):\n        \"\"\"Estimates the average upslope depression storage depth.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('upslope_depression_storage', args, callback) # returns 1 if error\n\n    def watershed(self, d8_pntr, pour_pts, output, esri_pntr=False, callback=None):\n        \"\"\"Identifies the watershed, or drainage basin, draining to a set of target cells.\n\n        Keyword arguments:\n\n        d8_pntr -- Input D8 pointer raster file. \n        pour_pts -- Input pour points (outlet) file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--pour_pts='{}'\".format(pour_pts))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('watershed', args, callback) # returns 1 if error\n\n    ##########################\n    # Image Processing Tools #\n    ##########################\n\n    def change_vector_analysis(self, date1, date2, magnitude, direction, callback=None):\n        \"\"\"Performs a change vector analysis on a two-date multi-spectral dataset.\n\n        Keyword arguments:\n\n        date1 -- Input raster files for the earlier date. \n        date2 -- Input raster files for the later date. \n        magnitude -- Output vector magnitude raster file. \n        direction -- Output vector Direction raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--date1='{}'\".format(date1))\n        args.append(\"--date2='{}'\".format(date2))\n        args.append(\"--magnitude='{}'\".format(magnitude))\n        args.append(\"--direction='{}'\".format(direction))\n        return self.run_tool('change_vector_analysis', args, callback) # returns 1 if error\n\n    def closing(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"A closing is a mathematical morphology operation involving an erosion (min filter) of a dilation (max filter) set.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('closing', args, callback) # returns 1 if error\n\n    def create_colour_composite(self, red, green, blue, output, opacity=None, enhance=True, zeros=False, callback=None):\n        \"\"\"Creates a colour-composite image from three bands of multispectral imagery.\n\n        Keyword arguments:\n\n        red -- Input red band image file. \n        green -- Input green band image file. \n        blue -- Input blue band image file. \n        opacity -- Input opacity band image file (optional). \n        output -- Output colour composite file. \n        enhance -- Optional flag indicating whether a balance contrast enhancement is performed. \n        zeros -- Optional flag to indicate if zeros are nodata values. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--red='{}'\".format(red))\n        args.append(\"--green='{}'\".format(green))\n        args.append(\"--blue='{}'\".format(blue))\n        if opacity is not None: args.append(\"--opacity='{}'\".format(opacity))\n        args.append(\"--output='{}'\".format(output))\n        if enhance: args.append(\"--enhance\")\n        if zeros: args.append(\"--zeros\")\n        return self.run_tool('create_colour_composite', args, callback) # returns 1 if error\n\n    def flip_image(self, i, output, direction=\"vertical\", callback=None):\n        \"\"\"Reflects an image in the vertical or horizontal axis.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        direction -- Direction of reflection; options include 'v' (vertical), 'h' (horizontal), and 'b' (both). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--direction={}\".format(direction))\n        return self.run_tool('flip_image', args, callback) # returns 1 if error\n\n    def ihs_to_rgb(self, intensity, hue, saturation, red=None, green=None, blue=None, output=None, callback=None):\n        \"\"\"Converts intensity, hue, and saturation (IHS) images into red, green, and blue (RGB) images.\n\n        Keyword arguments:\n\n        intensity -- Input intensity file. \n        hue -- Input hue file. \n        saturation -- Input saturation file. \n        red -- Output red band file. Optionally specified if colour-composite not specified. \n        green -- Output green band file. Optionally specified if colour-composite not specified. \n        blue -- Output blue band file. Optionally specified if colour-composite not specified. \n        output -- Output colour-composite file. Only used if individual bands are not specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--intensity='{}'\".format(intensity))\n        args.append(\"--hue='{}'\".format(hue))\n        args.append(\"--saturation='{}'\".format(saturation))\n        if red is not None: args.append(\"--red='{}'\".format(red))\n        if green is not None: args.append(\"--green='{}'\".format(green))\n        if blue is not None: args.append(\"--blue='{}'\".format(blue))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        return self.run_tool('ihs_to_rgb', args, callback) # returns 1 if error\n\n    def image_stack_profile(self, inputs, points, output, callback=None):\n        \"\"\"Plots an image stack profile (i.e. signature) for a set of points and multispectral images.\n\n        Keyword arguments:\n\n        inputs -- Input multispectral image files. \n        points -- Input vector points file. \n        output -- Output HTML file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--points='{}'\".format(points))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('image_stack_profile', args, callback) # returns 1 if error\n\n    def integral_image(self, i, output, callback=None):\n        \"\"\"Transforms an input image (summed area table) into its integral image equivalent.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('integral_image', args, callback) # returns 1 if error\n\n    def k_means_clustering(self, inputs, output, classes, out_html=None, max_iterations=10, class_change=2.0, initialize=\"diagonal\", min_class_size=10, callback=None):\n        \"\"\"Performs a k-means clustering operation on a multi-spectral dataset.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        out_html -- Output HTML report file. \n        classes -- Number of classes. \n        max_iterations -- Maximum number of iterations. \n        class_change -- Minimum percent of cells changed between iterations before completion. \n        initialize -- How to initialize cluster centres?. \n        min_class_size -- Minimum class size, in pixels. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        if out_html is not None: args.append(\"--out_html='{}'\".format(out_html))\n        args.append(\"--classes='{}'\".format(classes))\n        args.append(\"--max_iterations={}\".format(max_iterations))\n        args.append(\"--class_change={}\".format(class_change))\n        args.append(\"--initialize={}\".format(initialize))\n        args.append(\"--min_class_size={}\".format(min_class_size))\n        return self.run_tool('k_means_clustering', args, callback) # returns 1 if error\n\n    def line_thinning(self, i, output, callback=None):\n        \"\"\"Performs line thinning a on Boolean raster image; intended to be used with the RemoveSpurs tool.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('line_thinning', args, callback) # returns 1 if error\n\n    def modified_k_means_clustering(self, inputs, output, out_html=None, start_clusters=1000, merge_dist=None, max_iterations=10, class_change=2.0, callback=None):\n        \"\"\"Performs a modified k-means clustering operation on a multi-spectral dataset.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        out_html -- Output HTML report file. \n        start_clusters -- Initial number of clusters. \n        merge_dist -- Cluster merger distance. \n        max_iterations -- Maximum number of iterations. \n        class_change -- Minimum percent of cells changed between iterations before completion. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        if out_html is not None: args.append(\"--out_html='{}'\".format(out_html))\n        args.append(\"--start_clusters={}\".format(start_clusters))\n        if merge_dist is not None: args.append(\"--merge_dist='{}'\".format(merge_dist))\n        args.append(\"--max_iterations={}\".format(max_iterations))\n        args.append(\"--class_change={}\".format(class_change))\n        return self.run_tool('modified_k_means_clustering', args, callback) # returns 1 if error\n\n    def mosaic(self, inputs, output, method=\"cc\", callback=None):\n        \"\"\"Mosaics two or more images together.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        method -- Resampling method; options include 'nn' (nearest neighbour), 'bilinear', and 'cc' (cubic convolution). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--method={}\".format(method))\n        return self.run_tool('mosaic', args, callback) # returns 1 if error\n\n    def mosaic_with_feathering(self, input1, input2, output, method=\"cc\", weight=4.0, callback=None):\n        \"\"\"Mosaics two images together using a feathering technique in overlapping areas to reduce edge-effects.\n\n        Keyword arguments:\n\n        input1 -- Input raster file to modify. \n        input2 -- Input reference raster file. \n        output -- Output raster file. \n        method -- Resampling method; options include 'nn' (nearest neighbour), 'bilinear', and 'cc' (cubic convolution). \n        weight -- . \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--method={}\".format(method))\n        args.append(\"--weight={}\".format(weight))\n        return self.run_tool('mosaic_with_feathering', args, callback) # returns 1 if error\n\n    def normalized_difference_index(self, input1, input2, output, clip=0.0, correction=0.0, callback=None):\n        \"\"\"Calculate a normalized-difference index (NDI) from two bands of multispectral image data.\n\n        Keyword arguments:\n\n        input1 -- Input image 1 (e.g. near-infrared band). \n        input2 -- Input image 2 (e.g. red band). \n        output -- Output raster file. \n        clip -- Optional amount to clip the distribution tails by, in percent. \n        correction -- Optional adjustment value (e.g. 1, or 0.16 for the optimal soil adjusted vegetation index, OSAVI). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--clip={}\".format(clip))\n        args.append(\"--correction={}\".format(correction))\n        return self.run_tool('normalized_difference_index', args, callback) # returns 1 if error\n\n    def opening(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"An opening is a mathematical morphology operation involving a dilation (max filter) of an erosion (min filter) set.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('opening', args, callback) # returns 1 if error\n\n    def remove_spurs(self, i, output, iterations=10, callback=None):\n        \"\"\"Removes the spurs (pruning operation) from a Boolean line image; intended to be used on the output of the LineThinning tool.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        iterations -- Maximum number of iterations. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--iterations={}\".format(iterations))\n        return self.run_tool('remove_spurs', args, callback) # returns 1 if error\n\n    def resample(self, inputs, destination, method=\"cc\", callback=None):\n        \"\"\"Resamples one or more input images into a destination image.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        destination -- Destination raster file. \n        method -- Resampling method; options include 'nn' (nearest neighbour), 'bilinear', and 'cc' (cubic convolution). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--destination='{}'\".format(destination))\n        args.append(\"--method={}\".format(method))\n        return self.run_tool('resample', args, callback) # returns 1 if error\n\n    def rgb_to_ihs(self, intensity, hue, saturation, red=None, green=None, blue=None, composite=None, callback=None):\n        \"\"\"Converts red, green, and blue (RGB) images into intensity, hue, and saturation (IHS) images.\n\n        Keyword arguments:\n\n        red -- Input red band image file. Optionally specified if colour-composite not specified. \n        green -- Input green band image file. Optionally specified if colour-composite not specified. \n        blue -- Input blue band image file. Optionally specified if colour-composite not specified. \n        composite -- Input colour-composite image file. Only used if individual bands are not specified. \n        intensity -- Output intensity raster file. \n        hue -- Output hue raster file. \n        saturation -- Output saturation raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if red is not None: args.append(\"--red='{}'\".format(red))\n        if green is not None: args.append(\"--green='{}'\".format(green))\n        if blue is not None: args.append(\"--blue='{}'\".format(blue))\n        if composite is not None: args.append(\"--composite='{}'\".format(composite))\n        args.append(\"--intensity='{}'\".format(intensity))\n        args.append(\"--hue='{}'\".format(hue))\n        args.append(\"--saturation='{}'\".format(saturation))\n        return self.run_tool('rgb_to_ihs', args, callback) # returns 1 if error\n\n    def split_colour_composite(self, i, red=None, green=None, blue=None, callback=None):\n        \"\"\"This tool splits an RGB colour composite image into seperate multispectral images.\n\n        Keyword arguments:\n\n        i -- Input colour composite image file. \n        red -- Output red band file. \n        green -- Output green band file. \n        blue -- Output blue band file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if red is not None: args.append(\"--red='{}'\".format(red))\n        if green is not None: args.append(\"--green='{}'\".format(green))\n        if blue is not None: args.append(\"--blue='{}'\".format(blue))\n        return self.run_tool('split_colour_composite', args, callback) # returns 1 if error\n\n    def thicken_raster_line(self, i, output, callback=None):\n        \"\"\"Thickens single-cell wide lines within a raster image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('thicken_raster_line', args, callback) # returns 1 if error\n\n    def tophat_transform(self, i, output, filterx=11, filtery=11, variant=\"white\", callback=None):\n        \"\"\"Performs either a white or black top-hat transform on an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        variant -- Optional variant value. Options include 'white' and 'black'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        args.append(\"--variant={}\".format(variant))\n        return self.run_tool('tophat_transform', args, callback) # returns 1 if error\n\n    def write_function_memory_insertion(self, input1, input2, output, input3=None, callback=None):\n        \"\"\"Performs a write function memory insertion for single-band multi-date change detection.\n\n        Keyword arguments:\n\n        input1 -- Input raster file associated with the first date. \n        input2 -- Input raster file associated with the second date. \n        input3 -- Optional input raster file associated with the third date. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        if input3 is not None: args.append(\"--input3='{}'\".format(input3))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('write_function_memory_insertion', args, callback) # returns 1 if error\n\n    ##################################\n    # Image Processing Tools/Filters #\n    ##################################\n\n    def adaptive_filter(self, i, output, filterx=11, filtery=11, threshold=2.0, callback=None):\n        \"\"\"Performs an adaptive filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        threshold -- Difference from mean threshold, in standard deviations. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        args.append(\"--threshold={}\".format(threshold))\n        return self.run_tool('adaptive_filter', args, callback) # returns 1 if error\n\n    def bilateral_filter(self, i, output, sigma_dist=0.75, sigma_int=1.0, callback=None):\n        \"\"\"A bilateral filter is an edge-preserving smoothing filter introduced by Tomasi and Manduchi (1998).\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        sigma_dist -- Standard deviation in distance in pixels. \n        sigma_int -- Standard deviation in intensity in pixels. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--sigma_dist={}\".format(sigma_dist))\n        args.append(\"--sigma_int={}\".format(sigma_int))\n        return self.run_tool('bilateral_filter', args, callback) # returns 1 if error\n\n    def conservative_smoothing_filter(self, i, output, filterx=3, filtery=3, callback=None):\n        \"\"\"Performs a conservative-smoothing filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('conservative_smoothing_filter', args, callback) # returns 1 if error\n\n    def corner_detection(self, i, output, callback=None):\n        \"\"\"Identifies corner patterns in boolean images using hit-and-miss pattern matching.\n\n        Keyword arguments:\n\n        i -- Input boolean image. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('corner_detection', args, callback) # returns 1 if error\n\n    def diff_of_gaussian_filter(self, i, output, sigma1=2.0, sigma2=4.0, callback=None):\n        \"\"\"Performs a Difference of Gaussian (DoG) filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        sigma1 -- Standard deviation distance in pixels. \n        sigma2 -- Standard deviation distance in pixels. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--sigma1={}\".format(sigma1))\n        args.append(\"--sigma2={}\".format(sigma2))\n        return self.run_tool('diff_of_gaussian_filter', args, callback) # returns 1 if error\n\n    def diversity_filter(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Assigns each cell in the output grid the number of different values in a moving window centred on each grid cell in the input raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('diversity_filter', args, callback) # returns 1 if error\n\n    def edge_preserving_mean_filter(self, i, output, threshold, filter=11, callback=None):\n        \"\"\"Performs a simple edge-preserving mean filter on an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filter -- Size of the filter kernel. \n        threshold -- Maximum difference in values. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        args.append(\"--threshold='{}'\".format(threshold))\n        return self.run_tool('edge_preserving_mean_filter', args, callback) # returns 1 if error\n\n    def emboss_filter(self, i, output, direction=\"n\", clip=0.0, callback=None):\n        \"\"\"Performs an emboss filter on an image, similar to a hillshade operation.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        direction -- Direction of reflection; options include 'n', 's', 'e', 'w', 'ne', 'se', 'nw', 'sw'. \n        clip -- Optional amount to clip the distribution tails by, in percent. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--direction={}\".format(direction))\n        args.append(\"--clip={}\".format(clip))\n        return self.run_tool('emboss_filter', args, callback) # returns 1 if error\n\n    def fast_almost_gaussian_filter(self, i, output, sigma=1.8, callback=None):\n        \"\"\"Performs a fast approximate Gaussian filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        sigma -- Standard deviation distance in pixels. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--sigma={}\".format(sigma))\n        return self.run_tool('fast_almost_gaussian_filter', args, callback) # returns 1 if error\n\n    def gaussian_filter(self, i, output, sigma=0.75, callback=None):\n        \"\"\"Performs a Gaussian filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        sigma -- Standard deviation distance in pixels. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--sigma={}\".format(sigma))\n        return self.run_tool('gaussian_filter', args, callback) # returns 1 if error\n\n    def high_pass_filter(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Performs a high-pass filter on an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('high_pass_filter', args, callback) # returns 1 if error\n\n    def high_pass_median_filter(self, i, output, filterx=11, filtery=11, sig_digits=2, callback=None):\n        \"\"\"Performs a high pass median filter on an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        sig_digits -- Number of significant digits. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        args.append(\"--sig_digits={}\".format(sig_digits))\n        return self.run_tool('high_pass_median_filter', args, callback) # returns 1 if error\n\n    def k_nearest_mean_filter(self, i, output, filterx=11, filtery=11, k=5, callback=None):\n        \"\"\"A k-nearest mean filter is a type of edge-preserving smoothing filter.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        k -- k-value in pixels; this is the number of nearest-valued neighbours to use. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        args.append(\"-k={}\".format(k))\n        return self.run_tool('k_nearest_mean_filter', args, callback) # returns 1 if error\n\n    def laplacian_filter(self, i, output, variant=\"3x3(1)\", clip=0.0, callback=None):\n        \"\"\"Performs a Laplacian filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        variant -- Optional variant value. Options include 3x3(1), 3x3(2), 3x3(3), 3x3(4), 5x5(1), and 5x5(2) (default is 3x3(1)). \n        clip -- Optional amount to clip the distribution tails by, in percent. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--variant={}\".format(variant))\n        args.append(\"--clip={}\".format(clip))\n        return self.run_tool('laplacian_filter', args, callback) # returns 1 if error\n\n    def laplacian_of_gaussian_filter(self, i, output, sigma=0.75, callback=None):\n        \"\"\"Performs a Laplacian-of-Gaussian (LoG) filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        sigma -- Standard deviation in pixels. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--sigma={}\".format(sigma))\n        return self.run_tool('laplacian_of_gaussian_filter', args, callback) # returns 1 if error\n\n    def lee_sigma_filter(self, i, output, filterx=11, filtery=11, sigma=10.0, m=5.0, callback=None):\n        \"\"\"Performs a Lee (Sigma) smoothing filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        sigma -- Sigma value should be related to the standarad deviation of the distribution of image speckle noise. \n        m -- M-threshold value the minimum allowable number of pixels within the intensity range. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        args.append(\"--sigma={}\".format(sigma))\n        args.append(\"-m={}\".format(m))\n        return self.run_tool('lee_sigma_filter', args, callback) # returns 1 if error\n\n    def line_detection_filter(self, i, output, variant=\"vertical\", absvals=False, clip=0.0, callback=None):\n        \"\"\"Performs a line-detection filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        variant -- Optional variant value. Options include 'v' (vertical), 'h' (horizontal), '45', and '135' (default is 'v'). \n        absvals -- Optional flag indicating whether outputs should be absolute values. \n        clip -- Optional amount to clip the distribution tails by, in percent. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--variant={}\".format(variant))\n        if absvals: args.append(\"--absvals\")\n        args.append(\"--clip={}\".format(clip))\n        return self.run_tool('line_detection_filter', args, callback) # returns 1 if error\n\n    def majority_filter(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Assigns each cell in the output grid the most frequently occurring value (mode) in a moving window centred on each grid cell in the input raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('majority_filter', args, callback) # returns 1 if error\n\n    def maximum_filter(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Assigns each cell in the output grid the maximum value in a moving window centred on each grid cell in the input raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('maximum_filter', args, callback) # returns 1 if error\n\n    def mean_filter(self, i, output, filterx=3, filtery=3, callback=None):\n        \"\"\"Performs a mean filter (low-pass filter) on an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('mean_filter', args, callback) # returns 1 if error\n\n    def median_filter(self, i, output, filterx=11, filtery=11, sig_digits=2, callback=None):\n        \"\"\"Performs a median filter on an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        sig_digits -- Number of significant digits. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        args.append(\"--sig_digits={}\".format(sig_digits))\n        return self.run_tool('median_filter', args, callback) # returns 1 if error\n\n    def minimum_filter(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Assigns each cell in the output grid the minimum value in a moving window centred on each grid cell in the input raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('minimum_filter', args, callback) # returns 1 if error\n\n    def olympic_filter(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Performs an olympic smoothing filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('olympic_filter', args, callback) # returns 1 if error\n\n    def percentile_filter(self, i, output, filterx=11, filtery=11, sig_digits=2, callback=None):\n        \"\"\"Performs a percentile filter on an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        sig_digits -- Number of significant digits. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        args.append(\"--sig_digits={}\".format(sig_digits))\n        return self.run_tool('percentile_filter', args, callback) # returns 1 if error\n\n    def prewitt_filter(self, i, output, clip=0.0, callback=None):\n        \"\"\"Performs a Prewitt edge-detection filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        clip -- Optional amount to clip the distribution tails by, in percent. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--clip={}\".format(clip))\n        return self.run_tool('prewitt_filter', args, callback) # returns 1 if error\n\n    def range_filter(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Assigns each cell in the output grid the range of values in a moving window centred on each grid cell in the input raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('range_filter', args, callback) # returns 1 if error\n\n    def roberts_cross_filter(self, i, output, clip=0.0, callback=None):\n        \"\"\"Performs a Robert's cross edge-detection filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        clip -- Optional amount to clip the distribution tails by, in percent. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--clip={}\".format(clip))\n        return self.run_tool('roberts_cross_filter', args, callback) # returns 1 if error\n\n    def scharr_filter(self, i, output, clip=0.0, callback=None):\n        \"\"\"Performs a Scharr edge-detection filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        clip -- Optional amount to clip the distribution tails by, in percent. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--clip={}\".format(clip))\n        return self.run_tool('scharr_filter', args, callback) # returns 1 if error\n\n    def sobel_filter(self, i, output, variant=\"3x3\", clip=0.0, callback=None):\n        \"\"\"Performs a Sobel edge-detection filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        variant -- Optional variant value. Options include 3x3 and 5x5 (default is 3x3). \n        clip -- Optional amount to clip the distribution tails by, in percent (default is 0.0). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--variant={}\".format(variant))\n        args.append(\"--clip={}\".format(clip))\n        return self.run_tool('sobel_filter', args, callback) # returns 1 if error\n\n    def standard_deviation_filter(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Assigns each cell in the output grid the standard deviation of values in a moving window centred on each grid cell in the input raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('standard_deviation_filter', args, callback) # returns 1 if error\n\n    def total_filter(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Performs a total filter on an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('total_filter', args, callback) # returns 1 if error\n\n    def unsharp_masking(self, i, output, sigma=0.75, amount=100.0, threshold=0.0, callback=None):\n        \"\"\"An image sharpening technique that enhances edges.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        sigma -- Standard deviation distance in pixels. \n        amount -- A percentage and controls the magnitude of each overshoot. \n        threshold -- Controls the minimal brightness change that will be sharpened. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--sigma={}\".format(sigma))\n        args.append(\"--amount={}\".format(amount))\n        args.append(\"--threshold={}\".format(threshold))\n        return self.run_tool('unsharp_masking', args, callback) # returns 1 if error\n\n    def user_defined_weights_filter(self, i, weights, output, center=\"center\", normalize=False, callback=None):\n        \"\"\"Performs a user-defined weights filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        weights -- Input weights file. \n        output -- Output raster file. \n        center -- Kernel center cell; options include 'center', 'upper-left', 'upper-right', 'lower-left', 'lower-right'. \n        normalize -- Normalize kernel weights? This can reduce edge effects and lessen the impact of data gaps (nodata) but is not suited when the kernel weights sum to zero. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--weights='{}'\".format(weights))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--center={}\".format(center))\n        if normalize: args.append(\"--normalize\")\n        return self.run_tool('user_defined_weights_filter', args, callback) # returns 1 if error\n\n    ############################################\n    # Image Processing Tools/Image Enhancement #\n    ############################################\n\n    def balance_contrast_enhancement(self, i, output, band_mean=100.0, callback=None):\n        \"\"\"Performs a balance contrast enhancement on a colour-composite image of multispectral data.\n\n        Keyword arguments:\n\n        i -- Input colour composite image file. \n        output -- Output raster file. \n        band_mean -- Band mean value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--band_mean={}\".format(band_mean))\n        return self.run_tool('balance_contrast_enhancement', args, callback) # returns 1 if error\n\n    def correct_vignetting(self, i, pp, output, focal_length=304.8, image_width=228.6, n=4.0, callback=None):\n        \"\"\"Corrects the darkening of images towards corners.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        pp -- Input principal point file. \n        output -- Output raster file. \n        focal_length -- Camera focal length, in millimeters. \n        image_width -- Distance between photograph edges, in millimeters. \n        n -- The 'n' parameter. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--pp='{}'\".format(pp))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--focal_length={}\".format(focal_length))\n        args.append(\"--image_width={}\".format(image_width))\n        args.append(\"-n={}\".format(n))\n        return self.run_tool('correct_vignetting', args, callback) # returns 1 if error\n\n    def direct_decorrelation_stretch(self, i, output, k=0.5, clip=1.0, callback=None):\n        \"\"\"Performs a direct decorrelation stretch enhancement on a colour-composite image of multispectral data.\n\n        Keyword arguments:\n\n        i -- Input colour composite image file. \n        output -- Output raster file. \n        k -- Achromatic factor (k) ranges between 0 (no effect) and 1 (full saturation stretch), although typical values range from 0.3 to 0.7. \n        clip -- Optional percent to clip the upper tail by during the stretch. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"-k={}\".format(k))\n        args.append(\"--clip={}\".format(clip))\n        return self.run_tool('direct_decorrelation_stretch', args, callback) # returns 1 if error\n\n    def gamma_correction(self, i, output, gamma=0.5, callback=None):\n        \"\"\"Performs a gamma correction on an input images.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        gamma -- Gamma value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--gamma={}\".format(gamma))\n        return self.run_tool('gamma_correction', args, callback) # returns 1 if error\n\n    def gaussian_contrast_stretch(self, i, output, num_tones=256, callback=None):\n        \"\"\"Performs a Gaussian contrast stretch on input images.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        num_tones -- Number of tones in the output image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--num_tones={}\".format(num_tones))\n        return self.run_tool('gaussian_contrast_stretch', args, callback) # returns 1 if error\n\n    def histogram_equalization(self, i, output, num_tones=256, callback=None):\n        \"\"\"Performs a histogram equalization contrast enhancment on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        num_tones -- Number of tones in the output image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--num_tones={}\".format(num_tones))\n        return self.run_tool('histogram_equalization', args, callback) # returns 1 if error\n\n    def histogram_matching(self, i, histo_file, output, callback=None):\n        \"\"\"Alters the statistical distribution of a raster image matching it to a specified PDF.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        histo_file -- Input reference probability distribution function (pdf) text file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--histo_file='{}'\".format(histo_file))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('histogram_matching', args, callback) # returns 1 if error\n\n    def histogram_matching_two_images(self, input1, input2, output, callback=None):\n        \"\"\"This tool alters the cumulative distribution function of a raster image to that of another image.\n\n        Keyword arguments:\n\n        input1 -- Input raster file to modify. \n        input2 -- Input reference raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('histogram_matching_two_images', args, callback) # returns 1 if error\n\n    def min_max_contrast_stretch(self, i, output, min_val, max_val, num_tones=256, callback=None):\n        \"\"\"Performs a min-max contrast stretch on an input greytone image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        min_val -- Lower tail clip value. \n        max_val -- Upper tail clip value. \n        num_tones -- Number of tones in the output image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--min_val='{}'\".format(min_val))\n        args.append(\"--max_val='{}'\".format(max_val))\n        args.append(\"--num_tones={}\".format(num_tones))\n        return self.run_tool('min_max_contrast_stretch', args, callback) # returns 1 if error\n\n    def panchromatic_sharpening(self, pan, output, red=None, green=None, blue=None, composite=None, method=\"brovey\", callback=None):\n        \"\"\"Increases the spatial resolution of image data by combining multispectral bands with panchromatic data.\n\n        Keyword arguments:\n\n        red -- Input red band image file. Optionally specified if colour-composite not specified. \n        green -- Input green band image file. Optionally specified if colour-composite not specified. \n        blue -- Input blue band image file. Optionally specified if colour-composite not specified. \n        composite -- Input colour-composite image file. Only used if individual bands are not specified. \n        pan -- Input panchromatic band file. \n        output -- Output colour composite file. \n        method -- Options include 'brovey' (default) and 'ihs'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if red is not None: args.append(\"--red='{}'\".format(red))\n        if green is not None: args.append(\"--green='{}'\".format(green))\n        if blue is not None: args.append(\"--blue='{}'\".format(blue))\n        if composite is not None: args.append(\"--composite='{}'\".format(composite))\n        args.append(\"--pan='{}'\".format(pan))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--method={}\".format(method))\n        return self.run_tool('panchromatic_sharpening', args, callback) # returns 1 if error\n\n    def percentage_contrast_stretch(self, i, output, clip=1.0, tail=\"both\", num_tones=256, callback=None):\n        \"\"\"Performs a percentage linear contrast stretch on input images.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        clip -- Optional amount to clip the distribution tails by, in percent. \n        tail -- Specified which tails to clip; options include 'upper', 'lower', and 'both' (default is 'both'). \n        num_tones -- Number of tones in the output image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--clip={}\".format(clip))\n        args.append(\"--tail={}\".format(tail))\n        args.append(\"--num_tones={}\".format(num_tones))\n        return self.run_tool('percentage_contrast_stretch', args, callback) # returns 1 if error\n\n    def sigmoidal_contrast_stretch(self, i, output, cutoff=0.0, gain=1.0, num_tones=256, callback=None):\n        \"\"\"Performs a sigmoidal contrast stretch on input images.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        cutoff -- Cutoff value between 0.0 and 0.95. \n        gain -- Gain value. \n        num_tones -- Number of tones in the output image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--cutoff={}\".format(cutoff))\n        args.append(\"--gain={}\".format(gain))\n        args.append(\"--num_tones={}\".format(num_tones))\n        return self.run_tool('sigmoidal_contrast_stretch', args, callback) # returns 1 if error\n\n    def standard_deviation_contrast_stretch(self, i, output, stdev=2.0, num_tones=256, callback=None):\n        \"\"\"Performs a standard-deviation contrast stretch on input images.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        stdev -- Standard deviation clip value. \n        num_tones -- Number of tones in the output image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--stdev={}\".format(stdev))\n        args.append(\"--num_tones={}\".format(num_tones))\n        return self.run_tool('standard_deviation_contrast_stretch', args, callback) # returns 1 if error\n\n    ###############\n    # LiDAR Tools #\n    ###############\n\n    def classify_buildings_in_lidar(self, i, buildings, output, callback=None):\n        \"\"\"Reclassifies a LiDAR points that lie within vector building footprints.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        buildings -- Input vector polygons file. \n        output -- Output LiDAR file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--buildings='{}'\".format(buildings))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('classify_buildings_in_lidar', args, callback) # returns 1 if error\n\n    def classify_overlap_points(self, i, output, resolution=2.0, filter=False, callback=None):\n        \"\"\"Classifies or filters LAS points in regions of overlapping flight lines.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        resolution -- The size of the square area used to evaluate nearby points in the LiDAR data. \n        filter -- Filter out points from overlapping flightlines? If false, overlaps will simply be classified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--resolution={}\".format(resolution))\n        if filter: args.append(\"--filter\")\n        return self.run_tool('classify_overlap_points', args, callback) # returns 1 if error\n\n    def clip_lidar_to_polygon(self, i, polygons, output, callback=None):\n        \"\"\"Clips a LiDAR point cloud to a vector polygon or polygons.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        polygons -- Input vector polygons file. \n        output -- Output LiDAR file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--polygons='{}'\".format(polygons))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('clip_lidar_to_polygon', args, callback) # returns 1 if error\n\n    def erase_polygon_from_lidar(self, i, polygons, output, callback=None):\n        \"\"\"Erases (cuts out) a vector polygon or polygons from a LiDAR point cloud.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        polygons -- Input vector polygons file. \n        output -- Output LiDAR file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--polygons='{}'\".format(polygons))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('erase_polygon_from_lidar', args, callback) # returns 1 if error\n\n    def filter_lidar_classes(self, i, output, exclude_cls=None, callback=None):\n        \"\"\"Removes points in a LAS file with certain specified class values.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if exclude_cls is not None: args.append(\"--exclude_cls='{}'\".format(exclude_cls))\n        return self.run_tool('filter_lidar_classes', args, callback) # returns 1 if error\n\n    def filter_lidar_scan_angles(self, i, output, threshold, callback=None):\n        \"\"\"Removes points in a LAS file with scan angles greater than a threshold.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        threshold -- Scan angle threshold. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--threshold='{}'\".format(threshold))\n        return self.run_tool('filter_lidar_scan_angles', args, callback) # returns 1 if error\n\n    def find_flightline_edge_points(self, i, output, callback=None):\n        \"\"\"Identifies points along a flightline's edge in a LAS file.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('find_flightline_edge_points', args, callback) # returns 1 if error\n\n    def flightline_overlap(self, i=None, output=None, resolution=1.0, callback=None):\n        \"\"\"Reads a LiDAR (LAS) point file and outputs a raster containing the number of overlapping flight lines in each grid cell.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output file. \n        resolution -- Output raster's grid resolution. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--resolution={}\".format(resolution))\n        return self.run_tool('flightline_overlap', args, callback) # returns 1 if error\n\n    def height_above_ground(self, i=None, output=None, callback=None):\n        \"\"\"Normalizes a LiDAR point cloud, providing the height above the nearest ground-classified point.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file (including extension). \n        output -- Output raster file (including extension). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        return self.run_tool('height_above_ground', args, callback) # returns 1 if error\n\n    def las_to_ascii(self, inputs, callback=None):\n        \"\"\"Converts one or more LAS files into ASCII text files.\n\n        Keyword arguments:\n\n        inputs -- Input LiDAR files. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        return self.run_tool('las_to_ascii', args, callback) # returns 1 if error\n\n    def las_to_multipoint_shapefile(self, i=None, callback=None):\n        \"\"\"Converts one or more LAS files into MultipointZ vector Shapefiles. When the input parameter is not specified, the tool grids all LAS files contained within the working directory.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        return self.run_tool('las_to_multipoint_shapefile', args, callback) # returns 1 if error\n\n    def las_to_shapefile(self, i=None, callback=None):\n        \"\"\"Converts one or more LAS files into a vector Shapefile of POINT ShapeType.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        return self.run_tool('las_to_shapefile', args, callback) # returns 1 if error\n\n    def lidar_block_maximum(self, i=None, output=None, resolution=1.0, callback=None):\n        \"\"\"Creates a block-maximum raster from an input LAS file. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output file. \n        resolution -- Output raster's grid resolution. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--resolution={}\".format(resolution))\n        return self.run_tool('lidar_block_maximum', args, callback) # returns 1 if error\n\n    def lidar_block_minimum(self, i=None, output=None, resolution=1.0, callback=None):\n        \"\"\"Creates a block-minimum raster from an input LAS file. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output file. \n        resolution -- Output raster's grid resolution. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--resolution={}\".format(resolution))\n        return self.run_tool('lidar_block_minimum', args, callback) # returns 1 if error\n\n    def lidar_classify_subset(self, base, subset, output, subset_class, nonsubset_class=None, callback=None):\n        \"\"\"Classifies the values in one LiDAR point cloud that correpond with points in a subset cloud.\n\n        Keyword arguments:\n\n        base -- Input base LiDAR file. \n        subset -- Input subset LiDAR file. \n        output -- Output LiDAR file. \n        subset_class -- Subset point class value (must be 0-18; see LAS specifications). \n        nonsubset_class -- Non-subset point class value (must be 0-18; see LAS specifications). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--base='{}'\".format(base))\n        args.append(\"--subset='{}'\".format(subset))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--subset_class='{}'\".format(subset_class))\n        if nonsubset_class is not None: args.append(\"--nonsubset_class='{}'\".format(nonsubset_class))\n        return self.run_tool('lidar_classify_subset', args, callback) # returns 1 if error\n\n    def lidar_colourize(self, in_lidar, in_image, output, callback=None):\n        \"\"\"Adds the red-green-blue colour fields of a LiDAR (LAS) file based on an input image.\n\n        Keyword arguments:\n\n        in_lidar -- Input LiDAR file. \n        in_image -- Input colour image file. \n        output -- Output LiDAR file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--in_lidar='{}'\".format(in_lidar))\n        args.append(\"--in_image='{}'\".format(in_image))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('lidar_colourize', args, callback) # returns 1 if error\n\n    def lidar_construct_vector_tin(self, i=None, output=None, returns=\"all\", exclude_cls=None, minz=None, maxz=None, callback=None):\n        \"\"\"Creates a vector triangular irregular network (TIN) fitted to LiDAR points.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file (including extension). \n        output -- Output raster file (including extension). \n        returns -- Point return types to include; options are 'all' (default), 'last', 'first'. \n        exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. \n        minz -- Optional minimum elevation for inclusion in interpolation. \n        maxz -- Optional maximum elevation for inclusion in interpolation. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--returns={}\".format(returns))\n        if exclude_cls is not None: args.append(\"--exclude_cls='{}'\".format(exclude_cls))\n        if minz is not None: args.append(\"--minz='{}'\".format(minz))\n        if maxz is not None: args.append(\"--maxz='{}'\".format(maxz))\n        return self.run_tool('lidar_construct_vector_tin', args, callback) # returns 1 if error\n\n    def lidar_elevation_slice(self, i, output, minz=None, maxz=None, cls=False, inclassval=2, outclassval=1, callback=None):\n        \"\"\"Outputs all of the points within a LiDAR (LAS) point file that lie between a specified elevation range.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        minz -- Minimum elevation value (optional). \n        maxz -- Maximum elevation value (optional). \n        cls -- Optional boolean flag indicating whether points outside the range should be retained in output but reclassified. \n        inclassval -- Optional parameter specifying the class value assigned to points within the slice. \n        outclassval -- Optional parameter specifying the class value assigned to points within the slice. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if minz is not None: args.append(\"--minz='{}'\".format(minz))\n        if maxz is not None: args.append(\"--maxz='{}'\".format(maxz))\n        if cls: args.append(\"--class\")\n        args.append(\"--inclassval={}\".format(inclassval))\n        args.append(\"--outclassval={}\".format(outclassval))\n        return self.run_tool('lidar_elevation_slice', args, callback) # returns 1 if error\n\n    def lidar_ground_point_filter(self, i, output, radius=2.0, min_neighbours=0, slope_threshold=45.0, height_threshold=1.0, classify=True, slope_norm=True, height_above_ground=False, callback=None):\n        \"\"\"Identifies ground points within LiDAR dataset using a slope-based method.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        radius -- Search Radius. \n        min_neighbours -- The minimum number of neighbouring points within search areas. If fewer points than this threshold are idenfied during the fixed-radius search, a subsequent kNN search is performed to identify the k number of neighbours. \n        slope_threshold -- Maximum inter-point slope to be considered an off-terrain point. \n        height_threshold -- Inter-point height difference to be considered an off-terrain point. \n        classify -- Classify points as ground (2) or off-ground (1). \n        slope_norm -- Perform initial ground slope normalization?. \n        height_above_ground -- Transform output to height above average ground elevation?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--radius={}\".format(radius))\n        args.append(\"--min_neighbours={}\".format(min_neighbours))\n        args.append(\"--slope_threshold={}\".format(slope_threshold))\n        args.append(\"--height_threshold={}\".format(height_threshold))\n        if classify: args.append(\"--classify\")\n        if slope_norm: args.append(\"--slope_norm\")\n        if height_above_ground: args.append(\"--height_above_ground\")\n        return self.run_tool('lidar_ground_point_filter', args, callback) # returns 1 if error\n\n    def lidar_hex_binning(self, i, output, width, orientation=\"horizontal\", callback=None):\n        \"\"\"Hex-bins a set of LiDAR points.\n\n        Keyword arguments:\n\n        i -- Input base file. \n        output -- Output vector polygon file. \n        width -- The grid cell width. \n        orientation -- Grid Orientation, 'horizontal' or 'vertical'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--width='{}'\".format(width))\n        args.append(\"--orientation={}\".format(orientation))\n        return self.run_tool('lidar_hex_binning', args, callback) # returns 1 if error\n\n    def lidar_hillshade(self, i, output, azimuth=315.0, altitude=30.0, radius=1.0, callback=None):\n        \"\"\"Calculates a hillshade value for points within a LAS file and stores these data in the RGB field.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output file. \n        azimuth -- Illumination source azimuth in degrees. \n        altitude -- Illumination source altitude in degrees. \n        radius -- Search Radius. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--azimuth={}\".format(azimuth))\n        args.append(\"--altitude={}\".format(altitude))\n        args.append(\"--radius={}\".format(radius))\n        return self.run_tool('lidar_hillshade', args, callback) # returns 1 if error\n\n    def lidar_histogram(self, i, output, parameter=\"elevation\", clip=1.0, callback=None):\n        \"\"\"Creates a histogram of LiDAR data.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        parameter -- Parameter; options are 'elevation' (default), 'intensity', 'scan angle', 'class'. \n        clip -- Amount to clip distribution tails (in percent). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--parameter={}\".format(parameter))\n        args.append(\"--clip={}\".format(clip))\n        return self.run_tool('lidar_histogram', args, callback) # returns 1 if error\n\n    def lidar_idw_interpolation(self, i=None, output=None, parameter=\"elevation\", returns=\"all\", resolution=1.0, weight=1.0, radius=2.5, exclude_cls=None, minz=None, maxz=None, callback=None):\n        \"\"\"Interpolates LAS files using an inverse-distance weighted (IDW) scheme. When the input/output parameters are not specified, the tool interpolates all LAS files contained within the working directory.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file (including extension). \n        output -- Output raster file (including extension). \n        parameter -- Interpolation parameter; options are 'elevation' (default), 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data'. \n        returns -- Point return types to include; options are 'all' (default), 'last', 'first'. \n        resolution -- Output raster's grid resolution. \n        weight -- IDW weight value. \n        radius -- Search Radius. \n        exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. \n        minz -- Optional minimum elevation for inclusion in interpolation. \n        maxz -- Optional maximum elevation for inclusion in interpolation. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--parameter={}\".format(parameter))\n        args.append(\"--returns={}\".format(returns))\n        args.append(\"--resolution={}\".format(resolution))\n        args.append(\"--weight={}\".format(weight))\n        args.append(\"--radius={}\".format(radius))\n        if exclude_cls is not None: args.append(\"--exclude_cls='{}'\".format(exclude_cls))\n        if minz is not None: args.append(\"--minz='{}'\".format(minz))\n        if maxz is not None: args.append(\"--maxz='{}'\".format(maxz))\n        return self.run_tool('lidar_idw_interpolation', args, callback) # returns 1 if error\n\n    def lidar_info(self, i, output=None, vlr=True, geokeys=True, callback=None):\n        \"\"\"Prints information about a LiDAR (LAS) dataset, including header, point return frequency, and classification data and information about the variable length records (VLRs) and geokeys.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output HTML file for summary report. \n        vlr -- Flag indicating whether or not to print the variable length records (VLRs). \n        geokeys -- Flag indicating whether or not to print the geokeys. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        if vlr: args.append(\"--vlr\")\n        if geokeys: args.append(\"--geokeys\")\n        return self.run_tool('lidar_info', args, callback) # returns 1 if error\n\n    def lidar_join(self, inputs, output, callback=None):\n        \"\"\"Joins multiple LiDAR (LAS) files into a single LAS file.\n\n        Keyword arguments:\n\n        inputs -- Input LiDAR files. \n        output -- Output LiDAR file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('lidar_join', args, callback) # returns 1 if error\n\n    def lidar_kappa_index(self, input1, input2, output, class_accuracy, resolution=1.0, callback=None):\n        \"\"\"Performs a kappa index of agreement (KIA) analysis on the classifications of two LAS files.\n\n        Keyword arguments:\n\n        input1 -- Input LiDAR classification file. \n        input2 -- Input LiDAR reference file. \n        output -- Output HTML file. \n        class_accuracy -- Output classification accuracy raster file. \n        resolution -- Output raster's grid resolution. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--class_accuracy='{}'\".format(class_accuracy))\n        args.append(\"--resolution={}\".format(resolution))\n        return self.run_tool('lidar_kappa_index', args, callback) # returns 1 if error\n\n    def lidar_nearest_neighbour_gridding(self, i=None, output=None, parameter=\"elevation\", returns=\"all\", resolution=1.0, radius=2.5, exclude_cls=None, minz=None, maxz=None, callback=None):\n        \"\"\"Grids LAS files using nearest-neighbour scheme. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file (including extension). \n        output -- Output raster file (including extension). \n        parameter -- Interpolation parameter; options are 'elevation' (default), 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data'. \n        returns -- Point return types to include; options are 'all' (default), 'last', 'first'. \n        resolution -- Output raster's grid resolution. \n        radius -- Search Radius. \n        exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. \n        minz -- Optional minimum elevation for inclusion in interpolation. \n        maxz -- Optional maximum elevation for inclusion in interpolation. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--parameter={}\".format(parameter))\n        args.append(\"--returns={}\".format(returns))\n        args.append(\"--resolution={}\".format(resolution))\n        args.append(\"--radius={}\".format(radius))\n        if exclude_cls is not None: args.append(\"--exclude_cls='{}'\".format(exclude_cls))\n        if minz is not None: args.append(\"--minz='{}'\".format(minz))\n        if maxz is not None: args.append(\"--maxz='{}'\".format(maxz))\n        return self.run_tool('lidar_nearest_neighbour_gridding', args, callback) # returns 1 if error\n\n    def lidar_point_density(self, i=None, output=None, returns=\"all\", resolution=1.0, radius=2.5, exclude_cls=None, minz=None, maxz=None, callback=None):\n        \"\"\"Calculates the spatial pattern of point density for a LiDAR data set. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file (including extension). \n        output -- Output raster file (including extension). \n        returns -- Point return types to include; options are 'all' (default), 'last', 'first'. \n        resolution -- Output raster's grid resolution. \n        radius -- Search radius. \n        exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. \n        minz -- Optional minimum elevation for inclusion in interpolation. \n        maxz -- Optional maximum elevation for inclusion in interpolation. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--returns={}\".format(returns))\n        args.append(\"--resolution={}\".format(resolution))\n        args.append(\"--radius={}\".format(radius))\n        if exclude_cls is not None: args.append(\"--exclude_cls='{}'\".format(exclude_cls))\n        if minz is not None: args.append(\"--minz='{}'\".format(minz))\n        if maxz is not None: args.append(\"--maxz='{}'\".format(maxz))\n        return self.run_tool('lidar_point_density', args, callback) # returns 1 if error\n\n    def lidar_point_stats(self, i=None, resolution=1.0, num_points=True, num_pulses=False, avg_points_per_pulse=True, z_range=False, intensity_range=False, predom_class=False, callback=None):\n        \"\"\"Creates several rasters summarizing the distribution of LAS point data. When the input/output parameters are not specified, the tool works on all LAS files contained within the working directory.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        resolution -- Output raster's grid resolution. \n        num_points -- Flag indicating whether or not to output the number of points (returns) raster. \n        num_pulses -- Flag indicating whether or not to output the number of pulses raster. \n        avg_points_per_pulse -- Flag indicating whether or not to output the average number of points (returns) per pulse raster. \n        z_range -- Flag indicating whether or not to output the elevation range raster. \n        intensity_range -- Flag indicating whether or not to output the intensity range raster. \n        predom_class -- Flag indicating whether or not to output the predominant classification raster. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        args.append(\"--resolution={}\".format(resolution))\n        if num_points: args.append(\"--num_points\")\n        if num_pulses: args.append(\"--num_pulses\")\n        if avg_points_per_pulse: args.append(\"--avg_points_per_pulse\")\n        if z_range: args.append(\"--z_range\")\n        if intensity_range: args.append(\"--intensity_range\")\n        if predom_class: args.append(\"--predom_class\")\n        return self.run_tool('lidar_point_stats', args, callback) # returns 1 if error\n\n    def lidar_ransac_planes(self, i, output, radius=2.0, num_iter=50, num_samples=5, threshold=0.35, model_size=8, max_slope=80.0, classify=False, callback=None):\n        \"\"\"Performs a RANSAC analysis to identify points within a LiDAR point cloud that belong to linear planes.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        radius -- Search Radius. \n        num_iter -- Number of iterations. \n        num_samples -- Number of sample points on which to build the model. \n        threshold -- Threshold used to determine inlier points. \n        model_size -- Acceptable model size. \n        max_slope -- Maximum planar slope. \n        classify -- Classify points as ground (2) or off-ground (1). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--radius={}\".format(radius))\n        args.append(\"--num_iter={}\".format(num_iter))\n        args.append(\"--num_samples={}\".format(num_samples))\n        args.append(\"--threshold={}\".format(threshold))\n        args.append(\"--model_size={}\".format(model_size))\n        args.append(\"--max_slope={}\".format(max_slope))\n        if classify: args.append(\"--classify\")\n        return self.run_tool('lidar_ransac_planes', args, callback) # returns 1 if error\n\n    def lidar_rbf_interpolation(self, i=None, output=None, parameter=\"elevation\", returns=\"all\", resolution=1.0, num_points=20, exclude_cls=None, minz=None, maxz=None, func_type=\"ThinPlateSpline\", poly_order=\"none\", weight=5, callback=None):\n        \"\"\"Interpolates LAS files using a radial basis function (RBF) scheme. When the input/output parameters are not specified, the tool interpolates all LAS files contained within the working directory.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file (including extension). \n        output -- Output raster file (including extension). \n        parameter -- Interpolation parameter; options are 'elevation' (default), 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data'. \n        returns -- Point return types to include; options are 'all' (default), 'last', 'first'. \n        resolution -- Output raster's grid resolution. \n        num_points -- Number of points. \n        exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. \n        minz -- Optional minimum elevation for inclusion in interpolation. \n        maxz -- Optional maximum elevation for inclusion in interpolation. \n        func_type -- Radial basis function type; options are 'ThinPlateSpline' (default), 'PolyHarmonic', 'Gaussian', 'MultiQuadric', 'InverseMultiQuadric'. \n        poly_order -- Polynomial order; options are 'none' (default), 'constant', 'affine'. \n        weight -- Weight parameter used in basis function. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--parameter={}\".format(parameter))\n        args.append(\"--returns={}\".format(returns))\n        args.append(\"--resolution={}\".format(resolution))\n        args.append(\"--num_points={}\".format(num_points))\n        if exclude_cls is not None: args.append(\"--exclude_cls='{}'\".format(exclude_cls))\n        if minz is not None: args.append(\"--minz='{}'\".format(minz))\n        if maxz is not None: args.append(\"--maxz='{}'\".format(maxz))\n        args.append(\"--func_type={}\".format(func_type))\n        args.append(\"--poly_order={}\".format(poly_order))\n        args.append(\"--weight={}\".format(weight))\n        return self.run_tool('lidar_rbf_interpolation', args, callback) # returns 1 if error\n\n    def lidar_remove_duplicates(self, i, output, include_z=False, callback=None):\n        \"\"\"Removes duplicate points from a LiDAR data set.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        include_z -- Include z-values in point comparison?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if include_z: args.append(\"--include_z\")\n        return self.run_tool('lidar_remove_duplicates', args, callback) # returns 1 if error\n\n    def lidar_remove_outliers(self, i, output, radius=2.0, elev_diff=50.0, use_median=False, classify=True, callback=None):\n        \"\"\"Removes outliers (high and low points) in a LiDAR point cloud.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        radius -- Search Radius. \n        elev_diff -- Max. elevation difference. \n        use_median -- Optional flag indicating whether to use the difference from median elevation rather than mean. \n        classify -- Classify points as ground (2) or off-ground (1). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--radius={}\".format(radius))\n        args.append(\"--elev_diff={}\".format(elev_diff))\n        if use_median: args.append(\"--use_median\")\n        if classify: args.append(\"--classify\")\n        return self.run_tool('lidar_remove_outliers', args, callback) # returns 1 if error\n\n    def lidar_segmentation(self, i, output, radius=2.0, num_iter=50, num_samples=10, threshold=0.15, model_size=15, max_slope=80.0, norm_diff=10.0, maxzdiff=1.0, classes=False, ground=False, callback=None):\n        \"\"\"Segments a LiDAR point cloud based on differences in the orientation of fitted planar surfaces and point proximity.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        radius -- Search Radius. \n        num_iter -- Number of iterations. \n        num_samples -- Number of sample points on which to build the model. \n        threshold -- Threshold used to determine inlier points. \n        model_size -- Acceptable model size. \n        max_slope -- Maximum planar slope. \n        norm_diff -- Maximum difference in normal vectors, in degrees. \n        maxzdiff -- Maximum difference in elevation (z units) between neighbouring points of the same segment. \n        classes -- Segments don't cross class boundaries. \n        ground -- Classify the largest segment as ground points?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--radius={}\".format(radius))\n        args.append(\"--num_iter={}\".format(num_iter))\n        args.append(\"--num_samples={}\".format(num_samples))\n        args.append(\"--threshold={}\".format(threshold))\n        args.append(\"--model_size={}\".format(model_size))\n        args.append(\"--max_slope={}\".format(max_slope))\n        args.append(\"--norm_diff={}\".format(norm_diff))\n        args.append(\"--maxzdiff={}\".format(maxzdiff))\n        if classes: args.append(\"--classes\")\n        if ground: args.append(\"--ground\")\n        return self.run_tool('lidar_segmentation', args, callback) # returns 1 if error\n\n    def lidar_segmentation_based_filter(self, i, output, radius=5.0, norm_diff=2.0, maxzdiff=1.0, classify=False, callback=None):\n        \"\"\"Identifies ground points within LiDAR point clouds using a segmentation based approach.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output file. \n        radius -- Search Radius. \n        norm_diff -- Maximum difference in normal vectors, in degrees. \n        maxzdiff -- Maximum difference in elevation (z units) between neighbouring points of the same segment. \n        classify -- Classify points as ground (2) or off-ground (1). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--radius={}\".format(radius))\n        args.append(\"--norm_diff={}\".format(norm_diff))\n        args.append(\"--maxzdiff={}\".format(maxzdiff))\n        if classify: args.append(\"--classify\")\n        return self.run_tool('lidar_segmentation_based_filter', args, callback) # returns 1 if error\n\n    def lidar_thin(self, i, output, resolution=2.0, method=\"lowest\", save_filtered=False, callback=None):\n        \"\"\"Thins a LiDAR point cloud, reducing point density.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        resolution -- The size of the square area used to evaluate nearby points in the LiDAR data. \n        method -- Point selection method; options are 'first', 'last', 'lowest' (default), 'highest', 'nearest'. \n        save_filtered -- Save filtered points to seperate file?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--resolution={}\".format(resolution))\n        args.append(\"--method={}\".format(method))\n        if save_filtered: args.append(\"--save_filtered\")\n        return self.run_tool('lidar_thin', args, callback) # returns 1 if error\n\n    def lidar_thin_high_density(self, i, output, density, resolution=1.0, save_filtered=False, callback=None):\n        \"\"\"Thins points from high density areas within a LiDAR point cloud.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        resolution -- Output raster's grid resolution. \n        density -- Max. point density (points / m^3). \n        save_filtered -- Save filtered points to seperate file?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--resolution={}\".format(resolution))\n        args.append(\"--density='{}'\".format(density))\n        if save_filtered: args.append(\"--save_filtered\")\n        return self.run_tool('lidar_thin_high_density', args, callback) # returns 1 if error\n\n    def lidar_tile(self, i, width=1000.0, height=1000.0, origin_x=0.0, origin_y=0.0, min_points=2, callback=None):\n        \"\"\"Tiles a LiDAR LAS file into multiple LAS files.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        width -- Width of tiles in the X dimension; default 1000.0. \n        height -- Height of tiles in the Y dimension. \n        origin_x -- Origin point X coordinate for tile grid. \n        origin_y -- Origin point Y coordinate for tile grid. \n        min_points -- Minimum number of points contained in a tile for it to be saved. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--width={}\".format(width))\n        args.append(\"--height={}\".format(height))\n        args.append(\"--origin_x={}\".format(origin_x))\n        args.append(\"--origin_y={}\".format(origin_y))\n        args.append(\"--min_points={}\".format(min_points))\n        return self.run_tool('lidar_tile', args, callback) # returns 1 if error\n\n    def lidar_tile_footprint(self, output, i=None, hull=False, callback=None):\n        \"\"\"Creates a vector polygon of the convex hull of a LiDAR point cloud. When the input/output parameters are not specified, the tool works with all LAS files contained within the working directory.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output vector polygon file. \n        hull -- Identify the convex hull around points. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if hull: args.append(\"--hull\")\n        return self.run_tool('lidar_tile_footprint', args, callback) # returns 1 if error\n\n    def lidar_tin_gridding(self, i=None, output=None, parameter=\"elevation\", returns=\"all\", resolution=1.0, exclude_cls=None, minz=None, maxz=None, max_triangle_edge_length=None, callback=None):\n        \"\"\"Creates a raster grid based on a Delaunay triangular irregular network (TIN) fitted to LiDAR points.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file (including extension). \n        output -- Output raster file (including extension). \n        parameter -- Interpolation parameter; options are 'elevation' (default), 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data'. \n        returns -- Point return types to include; options are 'all' (default), 'last', 'first'. \n        resolution -- Output raster's grid resolution. \n        exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. \n        minz -- Optional minimum elevation for inclusion in interpolation. \n        maxz -- Optional maximum elevation for inclusion in interpolation. \n        max_triangle_edge_length -- Optional maximum triangle edge length; triangles larger than this size will not be gridded. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--parameter={}\".format(parameter))\n        args.append(\"--returns={}\".format(returns))\n        args.append(\"--resolution={}\".format(resolution))\n        if exclude_cls is not None: args.append(\"--exclude_cls='{}'\".format(exclude_cls))\n        if minz is not None: args.append(\"--minz='{}'\".format(minz))\n        if maxz is not None: args.append(\"--maxz='{}'\".format(maxz))\n        if max_triangle_edge_length is not None: args.append(\"--max_triangle_edge_length='{}'\".format(max_triangle_edge_length))\n        return self.run_tool('lidar_tin_gridding', args, callback) # returns 1 if error\n\n    def lidar_tophat_transform(self, i, output, radius=1.0, callback=None):\n        \"\"\"Performs a white top-hat transform on a Lidar dataset; as an estimate of height above ground, this is useful for modelling the vegetation canopy.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        radius -- Search Radius. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--radius={}\".format(radius))\n        return self.run_tool('lidar_tophat_transform', args, callback) # returns 1 if error\n\n    def normal_vectors(self, i, output, radius=1.0, callback=None):\n        \"\"\"Calculates normal vectors for points within a LAS file and stores these data (XYZ vector components) in the RGB field.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        radius -- Search Radius. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--radius={}\".format(radius))\n        return self.run_tool('normal_vectors', args, callback) # returns 1 if error\n\n    def select_tiles_by_polygon(self, indir, outdir, polygons, callback=None):\n        \"\"\"Copies LiDAR tiles overlapping with a polygon into an output directory.\n\n        Keyword arguments:\n\n        indir -- Input LAS file source directory. \n        outdir -- Output directory into which LAS files within the polygon are copied. \n        polygons -- Input vector polygons file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--indir='{}'\".format(indir))\n        args.append(\"--outdir='{}'\".format(outdir))\n        args.append(\"--polygons='{}'\".format(polygons))\n        return self.run_tool('select_tiles_by_polygon', args, callback) # returns 1 if error\n\n    ########################\n    # Math and Stats Tools #\n    ########################\n\n    def And(self, input1, input2, output, callback=None):\n        \"\"\"Performs a logical AND operator on two Boolean raster images.\n\n        Keyword arguments:\n\n        input1 -- Input raster file. \n        input2 -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('and', args, callback) # returns 1 if error\n\n    def Not(self, input1, input2, output, callback=None):\n        \"\"\"Performs a logical NOT operator on two Boolean raster images.\n\n        Keyword arguments:\n\n        input1 -- Input raster file. \n        input2 -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('not', args, callback) # returns 1 if error\n\n    def Or(self, input1, input2, output, callback=None):\n        \"\"\"Performs a logical OR operator on two Boolean raster images.\n\n        Keyword arguments:\n\n        input1 -- Input raster file. \n        input2 -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('or', args, callback) # returns 1 if error\n\n    def absolute_value(self, i, output, callback=None):\n        \"\"\"Calculates the absolute value of every cell in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('absolute_value', args, callback) # returns 1 if error\n\n    def add(self, input1, input2, output, callback=None):\n        \"\"\"Performs an addition operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('add', args, callback) # returns 1 if error\n\n    def anova(self, i, features, output, callback=None):\n        \"\"\"Performs an analysis of variance (ANOVA) test on a raster dataset.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        features -- Feature definition (or class) raster. \n        output -- Output HTML file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--features='{}'\".format(features))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('anova', args, callback) # returns 1 if error\n\n    def arc_cos(self, i, output, callback=None):\n        \"\"\"Returns the inverse cosine (arccos) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('arc_cos', args, callback) # returns 1 if error\n\n    def arc_sin(self, i, output, callback=None):\n        \"\"\"Returns the inverse sine (arcsin) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('arc_sin', args, callback) # returns 1 if error\n\n    def arc_tan(self, i, output, callback=None):\n        \"\"\"Returns the inverse tangent (arctan) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('arc_tan', args, callback) # returns 1 if error\n\n    def arcosh(self, i, output, callback=None):\n        \"\"\"Returns the inverse hyperbolic cosine (arcosh) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('arcosh', args, callback) # returns 1 if error\n\n    def arsinh(self, i, output, callback=None):\n        \"\"\"Returns the inverse hyperbolic sine (arsinh) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('arsinh', args, callback) # returns 1 if error\n\n    def artanh(self, i, output, callback=None):\n        \"\"\"Returns the inverse hyperbolic tangent (arctanh) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('artanh', args, callback) # returns 1 if error\n\n    def atan2(self, input_y, input_x, output, callback=None):\n        \"\"\"Returns the 2-argument inverse tangent (atan2).\n\n        Keyword arguments:\n\n        input_y -- Input y raster file or constant value (rise). \n        input_x -- Input x raster file or constant value (run). \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input_y='{}'\".format(input_y))\n        args.append(\"--input_x='{}'\".format(input_x))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('atan2', args, callback) # returns 1 if error\n\n    def attribute_correlation(self, i, output=None, callback=None):\n        \"\"\"Performs a correlation analysis on attribute fields from a vector database.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        return self.run_tool('attribute_correlation', args, callback) # returns 1 if error\n\n    def attribute_correlation_neighbourhood_analysis(self, i, field1, field2, radius=None, min_points=None, stat=\"pearson\", callback=None):\n        \"\"\"Performs a correlation on two input vector attributes within a neighbourhood search windows.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        field1 -- First input field name (dependent variable) in attribute table. \n        field2 -- Second input field name (independent variable) in attribute table. \n        radius -- Search Radius (in map units). \n        min_points -- Minimum number of points. \n        stat -- Correlation type; one of 'pearson' (default) and 'spearman'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field1='{}'\".format(field1))\n        args.append(\"--field2='{}'\".format(field2))\n        if radius is not None: args.append(\"--radius='{}'\".format(radius))\n        if min_points is not None: args.append(\"--min_points='{}'\".format(min_points))\n        args.append(\"--stat={}\".format(stat))\n        return self.run_tool('attribute_correlation_neighbourhood_analysis', args, callback) # returns 1 if error\n\n    def attribute_histogram(self, i, field, output, callback=None):\n        \"\"\"Creates a histogram for the field values of a vector's attribute table.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        field -- Input field name in attribute table. \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field='{}'\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('attribute_histogram', args, callback) # returns 1 if error\n\n    def attribute_scattergram(self, i, fieldx, fieldy, output, trendline=False, callback=None):\n        \"\"\"Creates a scattergram for two field values of a vector's attribute table.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        fieldx -- Input field name in attribute table for the x-axis. \n        fieldy -- Input field name in attribute table for the y-axis. \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        trendline -- Draw the trendline. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--fieldx='{}'\".format(fieldx))\n        args.append(\"--fieldy='{}'\".format(fieldy))\n        args.append(\"--output='{}'\".format(output))\n        if trendline: args.append(\"--trendline\")\n        return self.run_tool('attribute_scattergram', args, callback) # returns 1 if error\n\n    def ceil(self, i, output, callback=None):\n        \"\"\"Returns the smallest (closest to negative infinity) value that is greater than or equal to the values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('ceil', args, callback) # returns 1 if error\n\n    def cos(self, i, output, callback=None):\n        \"\"\"Returns the cosine (cos) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('cos', args, callback) # returns 1 if error\n\n    def cosh(self, i, output, callback=None):\n        \"\"\"Returns the hyperbolic cosine (cosh) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('cosh', args, callback) # returns 1 if error\n\n    def crispness_index(self, i, output=None, callback=None):\n        \"\"\"Calculates the Crispness Index, which is used to quantify how crisp (or conversely how fuzzy) a probability image is.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Optional output html file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        return self.run_tool('crispness_index', args, callback) # returns 1 if error\n\n    def cross_tabulation(self, input1, input2, output, callback=None):\n        \"\"\"Performs a cross-tabulation on two categorical images.\n\n        Keyword arguments:\n\n        input1 -- Input raster file 1. \n        input2 -- Input raster file 1. \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('cross_tabulation', args, callback) # returns 1 if error\n\n    def cumulative_distribution(self, i, output, callback=None):\n        \"\"\"Converts a raster image to its cumulative distribution function.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('cumulative_distribution', args, callback) # returns 1 if error\n\n    def decrement(self, i, output, callback=None):\n        \"\"\"Decreases the values of each grid cell in an input raster by 1.0 (see also InPlaceSubtract).\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('decrement', args, callback) # returns 1 if error\n\n    def divide(self, input1, input2, output, callback=None):\n        \"\"\"Performs a division operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('divide', args, callback) # returns 1 if error\n\n    def equal_to(self, input1, input2, output, callback=None):\n        \"\"\"Performs a equal-to comparison operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('equal_to', args, callback) # returns 1 if error\n\n    def exp(self, i, output, callback=None):\n        \"\"\"Returns the exponential (base e) of values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('exp', args, callback) # returns 1 if error\n\n    def exp2(self, i, output, callback=None):\n        \"\"\"Returns the exponential (base 2) of values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('exp2', args, callback) # returns 1 if error\n\n    def floor(self, i, output, callback=None):\n        \"\"\"Returns the largest (closest to positive infinity) value that is less than or equal to the values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('floor', args, callback) # returns 1 if error\n\n    def greater_than(self, input1, input2, output, incl_equals=False, callback=None):\n        \"\"\"Performs a greater-than comparison operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        incl_equals -- Perform a greater-than-or-equal-to operation. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        if incl_equals: args.append(\"--incl_equals\")\n        return self.run_tool('greater_than', args, callback) # returns 1 if error\n\n    def image_autocorrelation(self, inputs, output, contiguity=\"Rook\", callback=None):\n        \"\"\"Performs Moran's I analysis on two or more input images.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        contiguity -- Contiguity type. \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--contiguity={}\".format(contiguity))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('image_autocorrelation', args, callback) # returns 1 if error\n\n    def image_correlation(self, inputs, output=None, callback=None):\n        \"\"\"Performs image correlation on two or more input images.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        return self.run_tool('image_correlation', args, callback) # returns 1 if error\n\n    def image_correlation_neighbourhood_analysis(self, input1, input2, output1, output2, filter=11, stat=\"pearson\", callback=None):\n        \"\"\"Performs image correlation on two input images neighbourhood search windows.\n\n        Keyword arguments:\n\n        input1 -- Input raster file. \n        input2 -- Input raster file. \n        output1 -- Output correlation (r-value or rho) raster file. \n        output2 -- Output significance (p-value) raster file. \n        filter -- Size of the filter kernel. \n        stat -- Correlation type; one of 'pearson' (default) and 'spearman'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output1='{}'\".format(output1))\n        args.append(\"--output2='{}'\".format(output2))\n        args.append(\"--filter={}\".format(filter))\n        args.append(\"--stat={}\".format(stat))\n        return self.run_tool('image_correlation_neighbourhood_analysis', args, callback) # returns 1 if error\n\n    def image_regression(self, input1, input2, output, out_residuals=None, standardize=False, scattergram=False, num_samples=1000, callback=None):\n        \"\"\"Performs image regression analysis on two input images.\n\n        Keyword arguments:\n\n        input1 -- Input raster file (independent variable, X). \n        input2 -- Input raster file (dependent variable, Y). \n        output -- Output HTML file for regression summary report. \n        out_residuals -- Output raster regression resdidual file. \n        standardize -- Optional flag indicating whether to standardize the residuals map. \n        scattergram -- Optional flag indicating whether to output a scattergram. \n        num_samples -- Number of samples used to create scattergram. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        if out_residuals is not None: args.append(\"--out_residuals='{}'\".format(out_residuals))\n        if standardize: args.append(\"--standardize\")\n        if scattergram: args.append(\"--scattergram\")\n        args.append(\"--num_samples={}\".format(num_samples))\n        return self.run_tool('image_regression', args, callback) # returns 1 if error\n\n    def in_place_add(self, input1, input2, callback=None):\n        \"\"\"Performs an in-place addition operation (input1 += input2).\n\n        Keyword arguments:\n\n        input1 -- Input raster file. \n        input2 -- Input raster file or constant value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        return self.run_tool('in_place_add', args, callback) # returns 1 if error\n\n    def in_place_divide(self, input1, input2, callback=None):\n        \"\"\"Performs an in-place division operation (input1 /= input2).\n\n        Keyword arguments:\n\n        input1 -- Input raster file. \n        input2 -- Input raster file or constant value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        return self.run_tool('in_place_divide', args, callback) # returns 1 if error\n\n    def in_place_multiply(self, input1, input2, callback=None):\n        \"\"\"Performs an in-place multiplication operation (input1 *= input2).\n\n        Keyword arguments:\n\n        input1 -- Input raster file. \n        input2 -- Input raster file or constant value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        return self.run_tool('in_place_multiply', args, callback) # returns 1 if error\n\n    def in_place_subtract(self, input1, input2, callback=None):\n        \"\"\"Performs an in-place subtraction operation (input1 -= input2).\n\n        Keyword arguments:\n\n        input1 -- Input raster file. \n        input2 -- Input raster file or constant value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        return self.run_tool('in_place_subtract', args, callback) # returns 1 if error\n\n    def increment(self, i, output, callback=None):\n        \"\"\"Increases the values of each grid cell in an input raster by 1.0. (see also InPlaceAdd).\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('increment', args, callback) # returns 1 if error\n\n    def integer_division(self, input1, input2, output, callback=None):\n        \"\"\"Performs an integer division operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('integer_division', args, callback) # returns 1 if error\n\n    def is_no_data(self, i, output, callback=None):\n        \"\"\"Identifies NoData valued pixels in an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('is_no_data', args, callback) # returns 1 if error\n\n    def kappa_index(self, input1, input2, output, callback=None):\n        \"\"\"Performs a kappa index of agreement (KIA) analysis on two categorical raster files.\n\n        Keyword arguments:\n\n        input1 -- Input classification raster file. \n        input2 -- Input reference raster file. \n        output -- Output HTML file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('kappa_index', args, callback) # returns 1 if error\n\n    def ks_test_for_normality(self, i, output, num_samples=None, callback=None):\n        \"\"\"Evaluates whether the values in a raster are normally distributed.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output HTML file. \n        num_samples -- Number of samples. Leave blank to use whole image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if num_samples is not None: args.append(\"--num_samples='{}'\".format(num_samples))\n        return self.run_tool('ks_test_for_normality', args, callback) # returns 1 if error\n\n    def less_than(self, input1, input2, output, incl_equals=False, callback=None):\n        \"\"\"Performs a less-than comparison operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        incl_equals -- Perform a less-than-or-equal-to operation. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        if incl_equals: args.append(\"--incl_equals\")\n        return self.run_tool('less_than', args, callback) # returns 1 if error\n\n    def list_unique_values(self, i, field, output, callback=None):\n        \"\"\"Lists the unique values contained in a field witin a vector's attribute table.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        field -- Input field name in attribute table. \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field='{}'\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('list_unique_values', args, callback) # returns 1 if error\n\n    def ln(self, i, output, callback=None):\n        \"\"\"Returns the natural logarithm of values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('ln', args, callback) # returns 1 if error\n\n    def log10(self, i, output, callback=None):\n        \"\"\"Returns the base-10 logarithm of values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('log10', args, callback) # returns 1 if error\n\n    def log2(self, i, output, callback=None):\n        \"\"\"Returns the base-2 logarithm of values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('log2', args, callback) # returns 1 if error\n\n    def max(self, input1, input2, output, callback=None):\n        \"\"\"Performs a MAX operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('max', args, callback) # returns 1 if error\n\n    def min(self, input1, input2, output, callback=None):\n        \"\"\"Performs a MIN operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('min', args, callback) # returns 1 if error\n\n    def modulo(self, input1, input2, output, callback=None):\n        \"\"\"Performs a modulo operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('modulo', args, callback) # returns 1 if error\n\n    def multiply(self, input1, input2, output, callback=None):\n        \"\"\"Performs a multiplication operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('multiply', args, callback) # returns 1 if error\n\n    def negate(self, i, output, callback=None):\n        \"\"\"Changes the sign of values in a raster or the 0-1 values of a Boolean raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('negate', args, callback) # returns 1 if error\n\n    def not_equal_to(self, input1, input2, output, callback=None):\n        \"\"\"Performs a not-equal-to comparison operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('not_equal_to', args, callback) # returns 1 if error\n\n    def paired_sample_t_test(self, input1, input2, output, num_samples=None, callback=None):\n        \"\"\"Performs a 2-sample K-S test for significant differences on two input rasters.\n\n        Keyword arguments:\n\n        input1 -- First input raster file. \n        input2 -- Second input raster file. \n        output -- Output HTML file. \n        num_samples -- Number of samples. Leave blank to use whole image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        if num_samples is not None: args.append(\"--num_samples='{}'\".format(num_samples))\n        return self.run_tool('paired_sample_t_test', args, callback) # returns 1 if error\n\n    def power(self, input1, input2, output, callback=None):\n        \"\"\"Raises the values in grid cells of one rasters, or a constant value, by values in another raster or constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('power', args, callback) # returns 1 if error\n\n    def principal_component_analysis(self, inputs, output, num_comp=None, standardized=False, callback=None):\n        \"\"\"Performs a principal component analysis (PCA) on a multi-spectral dataset.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output HTML report file. \n        num_comp -- Number of component images to output; <= to num. input images. \n        standardized -- Perform standardized PCA?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        if num_comp is not None: args.append(\"--num_comp='{}'\".format(num_comp))\n        if standardized: args.append(\"--standardized\")\n        return self.run_tool('principal_component_analysis', args, callback) # returns 1 if error\n\n    def quantiles(self, i, output, num_quantiles=5, callback=None):\n        \"\"\"Transforms raster values into quantiles.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        num_quantiles -- Number of quantiles. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--num_quantiles={}\".format(num_quantiles))\n        return self.run_tool('quantiles', args, callback) # returns 1 if error\n\n    def random_field(self, base, output, callback=None):\n        \"\"\"Creates an image containing random values.\n\n        Keyword arguments:\n\n        base -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--base='{}'\".format(base))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('random_field', args, callback) # returns 1 if error\n\n    def random_sample(self, base, output, num_samples=1000, callback=None):\n        \"\"\"Creates an image containing randomly located sample grid cells with unique IDs.\n\n        Keyword arguments:\n\n        base -- Input raster file. \n        output -- Output raster file. \n        num_samples -- Number of samples. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--base='{}'\".format(base))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--num_samples={}\".format(num_samples))\n        return self.run_tool('random_sample', args, callback) # returns 1 if error\n\n    def raster_histogram(self, i, output, callback=None):\n        \"\"\"Creates a histogram from raster values.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('raster_histogram', args, callback) # returns 1 if error\n\n    def raster_summary_stats(self, i, callback=None):\n        \"\"\"Measures a rasters min, max, average, standard deviation, num. non-nodata cells, and total.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('raster_summary_stats', args, callback) # returns 1 if error\n\n    def reciprocal(self, i, output, callback=None):\n        \"\"\"Returns the reciprocal (i.e. 1 / z) of values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('reciprocal', args, callback) # returns 1 if error\n\n    def rescale_value_range(self, i, output, out_min_val, out_max_val, clip_min=None, clip_max=None, callback=None):\n        \"\"\"Performs a min-max contrast stretch on an input greytone image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        out_min_val -- New minimum value in output image. \n        out_max_val -- New maximum value in output image. \n        clip_min -- Optional lower tail clip value. \n        clip_max -- Optional upper tail clip value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--out_min_val='{}'\".format(out_min_val))\n        args.append(\"--out_max_val='{}'\".format(out_max_val))\n        if clip_min is not None: args.append(\"--clip_min='{}'\".format(clip_min))\n        if clip_max is not None: args.append(\"--clip_max='{}'\".format(clip_max))\n        return self.run_tool('rescale_value_range', args, callback) # returns 1 if error\n\n    def root_mean_square_error(self, i, base, callback=None):\n        \"\"\"Calculates the RMSE and other accuracy statistics.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        base -- Input base raster file used for comparison. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--base='{}'\".format(base))\n        return self.run_tool('root_mean_square_error', args, callback) # returns 1 if error\n\n    def round(self, i, output, callback=None):\n        \"\"\"Rounds the values in an input raster to the nearest integer value.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('round', args, callback) # returns 1 if error\n\n    def sin(self, i, output, callback=None):\n        \"\"\"Returns the sine (sin) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('sin', args, callback) # returns 1 if error\n\n    def sinh(self, i, output, callback=None):\n        \"\"\"Returns the hyperbolic sine (sinh) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('sinh', args, callback) # returns 1 if error\n\n    def square(self, i, output, callback=None):\n        \"\"\"Squares the values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('square', args, callback) # returns 1 if error\n\n    def square_root(self, i, output, callback=None):\n        \"\"\"Returns the square root of the values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('square_root', args, callback) # returns 1 if error\n\n    def subtract(self, input1, input2, output, callback=None):\n        \"\"\"Performs a differencing operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('subtract', args, callback) # returns 1 if error\n\n    def tan(self, i, output, callback=None):\n        \"\"\"Returns the tangent (tan) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('tan', args, callback) # returns 1 if error\n\n    def tanh(self, i, output, callback=None):\n        \"\"\"Returns the hyperbolic tangent (tanh) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('tanh', args, callback) # returns 1 if error\n\n    def to_degrees(self, i, output, callback=None):\n        \"\"\"Converts a raster from radians to degrees.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('to_degrees', args, callback) # returns 1 if error\n\n    def to_radians(self, i, output, callback=None):\n        \"\"\"Converts a raster from degrees to radians.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('to_radians', args, callback) # returns 1 if error\n\n    def trend_surface(self, i, output, order=1, callback=None):\n        \"\"\"Estimates the trend surface of an input raster file.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        order -- Polynomial order (1 to 10). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--order={}\".format(order))\n        return self.run_tool('trend_surface', args, callback) # returns 1 if error\n\n    def trend_surface_vector_points(self, i, field, output, cell_size, order=1, callback=None):\n        \"\"\"Estimates a trend surface from vector points.\n\n        Keyword arguments:\n\n        i -- Input vector Points file. \n        field -- Input field name in attribute table. \n        output -- Output raster file. \n        order -- Polynomial order (1 to 10). \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field='{}'\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--order={}\".format(order))\n        args.append(\"--cell_size='{}'\".format(cell_size))\n        return self.run_tool('trend_surface_vector_points', args, callback) # returns 1 if error\n\n    def truncate(self, i, output, num_decimals=None, callback=None):\n        \"\"\"Truncates the values in a raster to the desired number of decimal places.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        num_decimals -- Number of decimals left after truncation (default is zero). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if num_decimals is not None: args.append(\"--num_decimals='{}'\".format(num_decimals))\n        return self.run_tool('truncate', args, callback) # returns 1 if error\n\n    def turning_bands_simulation(self, base, output, range, iterations=1000, callback=None):\n        \"\"\"Creates an image containing random values based on a turning-bands simulation.\n\n        Keyword arguments:\n\n        base -- Input base raster file. \n        output -- Output file. \n        range -- The field's range, in xy-units, related to the extent of spatial autocorrelation. \n        iterations -- The number of iterations. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--base='{}'\".format(base))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--range='{}'\".format(range))\n        args.append(\"--iterations={}\".format(iterations))\n        return self.run_tool('turning_bands_simulation', args, callback) # returns 1 if error\n\n    def two_sample_ks_test(self, input1, input2, output, num_samples=None, callback=None):\n        \"\"\"Performs a 2-sample K-S test for significant differences on two input rasters.\n\n        Keyword arguments:\n\n        input1 -- First input raster file. \n        input2 -- Second input raster file. \n        output -- Output HTML file. \n        num_samples -- Number of samples. Leave blank to use whole image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        if num_samples is not None: args.append(\"--num_samples='{}'\".format(num_samples))\n        return self.run_tool('two_sample_ks_test', args, callback) # returns 1 if error\n\n    def wilcoxon_signed_rank_test(self, input1, input2, output, num_samples=None, callback=None):\n        \"\"\"Performs a 2-sample K-S test for significant differences on two input rasters.\n\n        Keyword arguments:\n\n        input1 -- First input raster file. \n        input2 -- Second input raster file. \n        output -- Output HTML file. \n        num_samples -- Number of samples. Leave blank to use whole image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        if num_samples is not None: args.append(\"--num_samples='{}'\".format(num_samples))\n        return self.run_tool('wilcoxon_signed_rank_test', args, callback) # returns 1 if error\n\n    def xor(self, input1, input2, output, callback=None):\n        \"\"\"Performs a logical XOR operator on two Boolean raster images.\n\n        Keyword arguments:\n\n        input1 -- Input raster file. \n        input2 -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('xor', args, callback) # returns 1 if error\n\n    def z_scores(self, i, output, callback=None):\n        \"\"\"Standardizes the values in an input raster by converting to z-scores.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('z_scores', args, callback) # returns 1 if error\n\n    def zonal_statistics(self, i, features, output=None, stat=\"mean\", out_table=None, callback=None):\n        \"\"\"Extracts descriptive statistics for a group of patches in a raster.\n\n        Keyword arguments:\n\n        i -- Input data raster file. \n        features -- Input feature definition raster file. \n        output -- Output raster file. \n        stat -- Statistic to extract, including 'mean', 'median', 'minimum', 'maximum', 'range', 'standard deviation', and 'total'. \n        out_table -- Output HTML Table file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--features='{}'\".format(features))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--stat={}\".format(stat))\n        if out_table is not None: args.append(\"--out_table='{}'\".format(out_table))\n        return self.run_tool('zonal_statistics', args, callback) # returns 1 if error\n\n    ###########################\n    # Stream Network Analysis #\n    ###########################\n\n    def distance_to_outlet(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Calculates the distance of stream grid cells to the channel network outlet cell.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('distance_to_outlet', args, callback) # returns 1 if error\n\n    def extract_streams(self, flow_accum, output, threshold, zero_background=False, callback=None):\n        \"\"\"Extracts stream grid cells from a flow accumulation raster.\n\n        Keyword arguments:\n\n        flow_accum -- Input raster D8 flow accumulation file. \n        output -- Output raster file. \n        threshold -- Threshold in flow accumulation values for channelization. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--flow_accum='{}'\".format(flow_accum))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--threshold='{}'\".format(threshold))\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('extract_streams', args, callback) # returns 1 if error\n\n    def extract_valleys(self, dem, output, variant=\"LQ\", line_thin=True, filter=5, callback=None):\n        \"\"\"Identifies potential valley bottom grid cells based on local topolography alone.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        variant -- Options include 'LQ' (lower quartile), 'JandR' (Johnston and Rosenfeld), and 'PandD' (Peucker and Douglas); default is 'LQ'. \n        line_thin -- Optional flag indicating whether post-processing line-thinning should be performed. \n        filter -- Optional argument (only used when variant='lq') providing the filter size, in grid cells, used for lq-filtering (default is 5). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--variant={}\".format(variant))\n        if line_thin: args.append(\"--line_thin\")\n        args.append(\"--filter={}\".format(filter))\n        return self.run_tool('extract_valleys', args, callback) # returns 1 if error\n\n    def farthest_channel_head(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Calculates the distance to the furthest upstream channel head for each stream cell.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('farthest_channel_head', args, callback) # returns 1 if error\n\n    def find_main_stem(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Finds the main stem, based on stream lengths, of each stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('find_main_stem', args, callback) # returns 1 if error\n\n    def hack_stream_order(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Assigns the Hack stream order to each tributary in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('hack_stream_order', args, callback) # returns 1 if error\n\n    def horton_stream_order(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Assigns the Horton stream order to each tributary in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('horton_stream_order', args, callback) # returns 1 if error\n\n    def length_of_upstream_channels(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Calculates the total length of channels upstream.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('length_of_upstream_channels', args, callback) # returns 1 if error\n\n    def long_profile(self, d8_pntr, streams, dem, output, esri_pntr=False, callback=None):\n        \"\"\"Plots the stream longitudinal profiles for one or more rivers.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        dem -- Input raster DEM file. \n        output -- Output HTML file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('long_profile', args, callback) # returns 1 if error\n\n    def long_profile_from_points(self, d8_pntr, points, dem, output, esri_pntr=False, callback=None):\n        \"\"\"Plots the longitudinal profiles from flow-paths initiating from a set of vector points.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        points -- Input vector points file. \n        dem -- Input raster DEM file. \n        output -- Output HTML file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--points='{}'\".format(points))\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('long_profile_from_points', args, callback) # returns 1 if error\n\n    def raster_streams_to_vector(self, streams, d8_pntr, output, esri_pntr=False, callback=None):\n        \"\"\"Converts a raster stream file into a vector file.\n\n        Keyword arguments:\n\n        streams -- Input raster streams file. \n        d8_pntr -- Input raster D8 pointer file. \n        output -- Output vector file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('raster_streams_to_vector', args, callback) # returns 1 if error\n\n    def rasterize_streams(self, streams, base, output, nodata=True, feature_id=False, callback=None):\n        \"\"\"Rasterizes vector streams based on Lindsay (2016) method.\n\n        Keyword arguments:\n\n        streams -- Input vector streams file. \n        base -- Input base raster file. \n        output -- Output raster file. \n        nodata -- Use NoData value for background?. \n        feature_id -- Use feature number as output value?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--base='{}'\".format(base))\n        args.append(\"--output='{}'\".format(output))\n        if nodata: args.append(\"--nodata\")\n        if feature_id: args.append(\"--feature_id\")\n        return self.run_tool('rasterize_streams', args, callback) # returns 1 if error\n\n    def remove_short_streams(self, d8_pntr, streams, output, min_length, esri_pntr=False, callback=None):\n        \"\"\"Removes short first-order streams from a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        min_length -- Minimum tributary length (in map units) used for network prunning. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--min_length='{}'\".format(min_length))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('remove_short_streams', args, callback) # returns 1 if error\n\n    def shreve_stream_magnitude(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Assigns the Shreve stream magnitude to each link in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('shreve_stream_magnitude', args, callback) # returns 1 if error\n\n    def strahler_stream_order(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Assigns the Strahler stream order to each link in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('strahler_stream_order', args, callback) # returns 1 if error\n\n    def stream_link_class(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Identifies the exterior/interior links and nodes in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('stream_link_class', args, callback) # returns 1 if error\n\n    def stream_link_identifier(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Assigns a unique identifier to each link in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('stream_link_identifier', args, callback) # returns 1 if error\n\n    def stream_link_length(self, d8_pntr, linkid, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Estimates the length of each link (or tributary) in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        linkid -- Input raster streams link ID (or tributary ID) file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--linkid='{}'\".format(linkid))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('stream_link_length', args, callback) # returns 1 if error\n\n    def stream_link_slope(self, d8_pntr, linkid, dem, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Estimates the average slope of each link (or tributary) in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        linkid -- Input raster streams link ID (or tributary ID) file. \n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--linkid='{}'\".format(linkid))\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('stream_link_slope', args, callback) # returns 1 if error\n\n    def stream_slope_continuous(self, d8_pntr, streams, dem, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Estimates the slope of each grid cell in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('stream_slope_continuous', args, callback) # returns 1 if error\n\n    def topological_stream_order(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Assigns each link in a stream network its topological order.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('topological_stream_order', args, callback) # returns 1 if error\n\n    def tributary_identifier(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Assigns a unique identifier to each tributary in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('tributary_identifier', args, callback) # returns 1 if error\n"
  },
  {
    "path": "WBT/UserManual.txt",
    "content": "The WhiteboxTools User Manual is now available online at:\n\nhttps://www.whiteboxgeo.com/manual/wbt_book/preface.html\n\nPlease see the manual for details on usage and for descriptions of available tools. \nThe PDF version of the User Manual is no longer distributed along with the software."
  },
  {
    "path": "WBT/__init__.py",
    "content": ""
  },
  {
    "path": "WBT/plugins/conditional_evaluation.json",
    "content": "{\n    \"tool_name\": \"ConditionalEvaluation\",\n    \"exe\": \"conditional_evaluation\",\n    \"short_description\": \"Performs a conditional evaluation (if-then-else) operation on a raster.\",\n    \"toolbox\": \"Math and Stats Tools\",\n    \"license\": \"MIT\",\n    \"example\": \".*EXE_NAME -r=ConditionalEvaluation -i=DEM.tif --statement='value > 2500.0' --true=2500.0 --false=DEM.tif --output=onlyLowPlaces.tif\",\n    \"parameters\": [\n        {\n            \"name\": \"Input Raster\",\n            \"flags\": [\"-i\", \"--input\"],\n            \"description\": \"Name of the input raster file.\",\n            \"parameter_type\": {\"ExistingFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Conditional Statement e.g. value > 35.0:\",\n            \"flags\": [\"--statement\"],\n            \"description\": \"Conditional statement e.g. value > 35.0. This statement must be a valid Rust statement.\",\n            \"parameter_type\": \"String\",\n            \"default_value\": \"\",\n            \"optional\": false\n        },\n        {\n            \"name\": \"Value Where TRUE (Raster File Or Constant Value)\",\n            \"flags\": [\"--true\"],\n            \"description\": \"Value where condition evaluates TRUE (input raster or constant value).\",\n            \"parameter_type\": {\"ExistingFileOrFloat\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": true\n        },\n        {\n            \"name\": \"Value Where FALSE (Raster File Or Constant Value)\",\n            \"flags\": [\"--false\"],\n            \"description\": \"Value where condition evaluates FALSE (input raster or constant value).\",\n            \"parameter_type\": {\"ExistingFileOrFloat\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": true\n        },\n        {\n            \"name\": \"Output Raster File\",\n            \"flags\": [\"--output\"],\n            \"description\": \"Name of the output raster file.\",\n            \"parameter_type\": {\"NewFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/conditioned_latin_hypercube.json",
    "content": "{\n    \"tool_name\": \"ConditionedLatinHypercube\",\n    \"exe\": \"conditioned_latin_hypercube\",\n    \"short_description\": \"Implements conditioned Latin Hypercube sampling.\",\n    \"toolbox\": \"Math and Stats Tools\",\n    \"license\": \"MIT\",\n    \"example\": \".*EXE_NAME run -i=Raster1.tif;Raster2.tif --output=sites.shp --samples=500\",\n    \"parameters\": [\n        {\n            \"name\": \"Input Raster\",\n            \"flags\": [\"-i\", \"--inputs\"],\n            \"description\": \"Name of the input raster file\",\n            \"parameter_type\": {\"FileList\":{\"ExistingFile\":\"Raster\"}},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output shapefile\",\n            \"flags\": [\"-o\", \"--output\"],\n            \"description\": \"Output shapefile\",\n            \"parameter_type\": {\"NewFile\":{\"Vector\":\"Point\"}},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Number of sample sites\",\n            \"flags\": [\"--samples\"],\n            \"description\": \"Number of sample sites returned\",\n            \"parameter_type\": \"Integer\",\n            \"default_value\": \"500\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Number of resampling iterations\",\n            \"flags\": [\"--iterations\"],\n            \"description\": \"Maximum iterations (if stopping criteria not reached).\",\n            \"parameter_type\": \"Integer\",\n            \"default_value\": \"25000\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"RNG seed\",\n            \"flags\": [\"--seed\"],\n            \"description\": \"Seed for RNG consistency\",\n            \"parameter_type\": \"Integer\",\n            \"default_value\": null,\n            \"optional\": true\n        },\n        {\n            \"name\": \"Random resample probability\",\n            \"flags\": [\"--prob\"],\n            \"description\": \"Probability of random resample or resampling worst strata between [0,1].\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"0.5\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Objective function threshold.\",\n            \"flags\": [\"--threshold\"],\n            \"description\": \"Objective function values below the theshold stop the resampling iterations.\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": null,\n            \"optional\": true\n        },\n        {\n            \"name\": \"Initial annealing temperature\",\n            \"flags\": [\"--temp\"],\n            \"description\": \"Initial annealing temperature between [0,1].\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"1.0\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Temperature decay factor\",\n            \"flags\": [\"--temp_decay\"],\n            \"description\": \"Annealing temperature decay proportion between [0,1]. Reduce temperature by this proportion each annealing cycle.\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"0.05\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Annealing cycle duration\",\n            \"flags\": [\"--cycle\"],\n            \"description\": \"Number of iterations before decaying annealing temperature.\",\n            \"parameter_type\": \"Integer\",\n            \"default_value\": \"10\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Average the continuous Obj. Func.\",\n            \"flags\": [\"--average\"],\n            \"description\": \"Weight the continuous objective funtion by the 1/N contributing strata.\",\n            \"parameter_type\": \"Boolean\",\n            \"default_value\": \"false\",\n            \"optional\": true\n        }\n    ]\n}\n"
  },
  {
    "path": "WBT/plugins/edge_contamination.json",
    "content": "{\n    \"tool_name\": \"EdgeContamination\",\n    \"exe\": \"edge_contamination\",\n    \"short_description\": \"Identifies grid cells within an input DEM that may be impacted by edge contamination for hydrological applications.\",\n    \"toolbox\": \"Hydrological Analysis\",\n    \"license\": \"MIT\",\n    \"example\": \".*EXE_NAME -r=EdgeContamination --dem=DEM.tif --output=edge_cont.tif --flow_type='dinf'\",\n    \"parameters\": [\n        {\n            \"name\": \"Input DEM Raster\",\n            \"flags\": [\"-d\", \"--dem\"],\n            \"description\": \"Name of the input DEM raster file; must be depressionless.\",\n            \"parameter_type\": {\"ExistingFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output Raster File\",\n            \"flags\": [\"-o\", \"--output\"],\n            \"description\": \"Name of the output raster file.\",\n            \"parameter_type\": {\"NewFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Flow Type\",\n            \"flags\": [\"--flow_type\"],\n            \"description\": \"Flow algorithm type, one of 'd8', 'mfd', or 'dinf'\",\n            \"parameter_type\": {\"OptionList\": [\"d8\", \"mfd\", \"dinf\"]},\n            \"default_value\": \"mfd\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Z Conversion Factor\",\n            \"flags\": [\"--zfactor\"],\n            \"description\": \"Optional multiplier for when the vertical and horizontal units are not the same.\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"\",\n            \"optional\": true\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/exposure_towards_wind_flux.json",
    "content": "{\n    \"tool_name\": \"ExposureTowardsWindFlux\",\n    \"exe\": \"exposure_towards_wind_flux\",\n    \"short_description\": \"Evaluates hydrologic connectivity within a DEM\",\n    \"toolbox\": \"Geomorphometric Analysis\",\n    \"license\": \"MIT\",\n    \"example\": \".*EXE_NAME -r=ExposureTowardsWindFlux -dem=input.tif -o=exposure.tif --azimuth=35.0 --max_dist=500.0\",\n    \"parameters\": [\n        {\n            \"name\": \"Input DEM Raster\",\n            \"flags\": [\"-d\", \"--dem\"],\n            \"description\": \"Name of the input DEM raster file.\",\n            \"parameter_type\": {\"ExistingFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output Raster File\",\n            \"flags\": [\"-o\", \"--output\"],\n            \"description\": \"Name of the output raster file.\",\n            \"parameter_type\": {\"NewFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Wind Azimuth (in degrees)\",\n            \"flags\": [\"--azimuth\"],\n            \"description\": \"Wind azimuth, in degrees.\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"\",\n            \"optional\": false\n        },\n        {\n            \"name\": \"Maximum Search Distance\",\n            \"flags\": [\"--max_dist\"],\n            \"description\": \"Optional maximum search distance. Minimum value is 5 x cell size.\",\n            \"parameter_type\": \"Integer\",\n            \"default_value\": \"\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Z Conversion Factor\",\n            \"flags\": [\"--zfactor\"],\n            \"description\": \"Optional multiplier for when the vertical and horizontal units are not the same.\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"\",\n            \"optional\": true\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/gaussian_scale_space.json",
    "content": "{\n    \"tool_name\": \"GaussianScaleSpace\",\n    \"exe\": \"gaussian_scale_space\",\n    \"short_description\": \"Uses the fast Gaussian approximation algorithm to produce scaled land-surface parameter measurements from an input DEM.\",\n    \"toolbox\": \"Geomorphometric Analysis\",\n    \"license\": \"MIT\",\n    \"example\": \".*EXE_NAME -r=GaussianScaleSpace --dem=DEM.tif --output=slope.tif --output_zscore=slope_z.tif --output_scale=slope_scale.tif --sigma=0.5 --step=1.0 --num_steps=100 --lsp='Slope'\",\n    \"parameters\": [\n        {\n            \"name\": \"Input DEM Raster\",\n            \"flags\": [\"-d\", \"--dem\"],\n            \"description\": \"Name of the input DEM raster file.\",\n            \"parameter_type\": {\"ExistingFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Input Vector Points File\",\n            \"flags\": [\"-p\", \"--points\"],\n            \"description\": \"Name of the input vector points shapefile.\",\n            \"parameter_type\": {\"ExistingFile\":{\"Vector\":\"Point\"}},\n            \"default_value\": null,\n            \"optional\": true\n        },\n        {\n            \"name\": \"Output Land-surface Parameter Raster File\",\n            \"flags\": [\"-o\", \"--output\"],\n            \"description\": \"Name of the output land-surface parameter raster file.\",\n            \"parameter_type\": {\"NewFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output z-Score Raster File\",\n            \"flags\": [\"--output_zscore\"],\n            \"description\": \"Name of the output z-score raster file.\",\n            \"parameter_type\": {\"NewFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output Scale Raster File\",\n            \"flags\": [\"--output_scale\"],\n            \"description\": \"Name of the output scale raster file.\",\n            \"parameter_type\": {\"NewFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Starting Scale\",\n            \"flags\": [\"--sigma\"],\n            \"description\": \"Initial sigma value (cells).\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"0.5\",\n            \"optional\": false\n        },\n        {\n            \"name\": \"Step Size\",\n            \"flags\": [\"--step\"],\n            \"description\": \"Step size as any positive non-zero integer.\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"0.5\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Number of Steps\",\n            \"flags\": [\"--num_steps\"],\n            \"description\": \"Number of steps.\",\n            \"parameter_type\": \"Integer\",\n            \"default_value\": \"10\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Land-surface Parameter to Calculate\",\n            \"flags\": [\"--lsp\"],\n            \"description\": \"Output land-surface parameter; one of 'AnisotropyLTP', 'Aspect', 'DiffMeanElev', 'Eastness', 'Elevation', 'Hillshade', 'MeanCurvature', 'Northness', 'PlanCurvature', 'ProfileCurvature', 'Ruggedness', 'Slope', 'TanCurvature', 'TotalCurvature'.\",\n            \"parameter_type\": {\"OptionList\": [\"AnisotropyLTP\", \"Aspect\", \"DiffMeanElev\", \"Eastness\", \"Elevation\", \"Hillshade\", \"MeanCurvature\", \"Northness\", \"PlanCurvature\", \"ProfileCurvature\", \"Ruggedness\", \"Slope\", \"TanCurvature\", \"TotalCurvature\"]},\n            \"default_value\": \"Slope\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Z Conversion Factor\",\n            \"flags\": [\"--z_factor\"],\n            \"description\": \"Optional multiplier for when the vertical and horizontal units are not the same.\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": null,\n            \"optional\": true\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/heat_map.json",
    "content": "{\n    \"tool_name\": \"HeatMap\",\n    \"exe\": \"heat_map\",\n    \"short_description\": \"Calculates a heat map, or kernel density estimation (KDE), for an input point set.\",\n    \"toolbox\": \"GIS Analysis\",\n    \"license\": \"Proprietary\",\n    \"example\": \">> .*EXE_NAME -r=HeatMap -i=points.shp -o=density.tif --bandwidth=1000.0 --kernel='quartic' --cell_size=10.0\",\n    \"parameters\": [\n        {\n            \"name\": \"Input Points\",\n            \"flags\": [\"-i\", \"--input\"],\n            \"description\": \"Name of the input points shapefile.\",\n            \"parameter_type\": {\"ExistingFile\":{\"Vector\":\"Point\"}},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Weight Field Name (Optional)\",\n            \"flags\": [\"--weights\", \"--weight_field\"],\n            \"description\": \"Optional name of the attribute containing point weight.\",\n            \"parameter_type\": \"String\",\n            \"default_value\": null,\n            \"optional\": true\n        },\n        {\n            \"name\": \"Output Raster Image\",\n            \"flags\": [\"-o\", \"--output\"],\n            \"description\": \"Name of the output raster image file.\",\n            \"parameter_type\": {\"NewFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Bandwidth\",\n            \"flags\": [\"--bandwidth\"],\n            \"description\": \"Bandwidth (metres).\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"\",\n            \"optional\": false\n        },\n        {\n            \"name\": \"Kernel Type\",\n            \"flags\": [\"--kernel\"],\n            \"description\": \"Kernel type; one of 'uniform', 'triangular', 'epanechnikov', 'quartic', 'triweight', 'tricube', 'gaussian', 'cosine', 'logistic', 'sigmoid', 'silverman'.\",\n            \"parameter_type\": {\"OptionList\": [\"uniform\", \"triangular\", \"epanechnikov\", \"quartic\", \"triweight\", \"tricube\", \"gaussian\", \"cosine\", \"logistic\", \"sigmoid\", \"silverman\"]},\n            \"default_value\": \"quartic\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Output Raster Cell Size (Optional)\",\n            \"flags\": [\"--cell_size\"],\n            \"description\": \"Optionally specified cell size of output raster, in metres. Not used when base raster is specified.\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Base Raster (Optional)\",\n            \"flags\": [\"--base\"],\n            \"description\": \"Optionally specified input base raster file. Not used when a cell size is specified.\",\n            \"parameter_type\": {\"ExistingFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": true\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/individual_tree_detection.json",
    "content": "{\n    \"tool_name\": \"IndividualTreeDetection\",\n    \"exe\": \"individual_tree_detection\",\n    \"short_description\": \"Identifies points in a LiDAR point cloud that are associated with the tops of individual trees.\",\n    \"toolbox\": \"LiDAR Tools\",\n    \"license\": \"Proprietary\",\n    \"example\": \">> .*EXE_NAME -r=IndividualTreeDetection -i=points.laz -o=tree_tops.shp --min_search_radius=1.5 --min_height=2.0 --max_search_radius=8.0 --max_height=30.0 --only_use_veg\",\n    \"parameters\": [\n        {\n            \"name\": \"Input LiDAR File\",\n            \"flags\": [\"-i\", \"--input\"],\n            \"description\": \"Name of the input LiDAR file.\",\n            \"parameter_type\": {\"ExistingFile\":\"Lidar\"},\n            \"default_value\": null,\n            \"optional\": true\n        },\n        {\n            \"name\": \"Output Vector\",\n            \"flags\": [\"-o\", \"--output\"],\n            \"description\": \"Name of the output vector points file.\",\n            \"parameter_type\": {\"NewFile\":{\"Vector\":\"Point\"}},\n            \"default_value\": null,\n            \"optional\": true\n        },\n        {\n            \"name\": \"Min. Search Radius\",\n            \"flags\": [\"--min_search_radius\"],\n            \"description\": \"Minimum search radius (m).\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"1.0\",\n            \"optional\": false\n        },\n        {\n            \"name\": \"Min. Height\",\n            \"flags\": [\"--min_height\"],\n            \"description\": \"Minimum height (m).\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"0.0\",\n            \"optional\": false\n        },\n        {\n            \"name\": \"Max. Search Radius\",\n            \"flags\": [\"--max_search_radius\"],\n            \"description\": \"Maximum search radius (m).\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Max. Height\",\n            \"flags\": [\"--max_height\"],\n            \"description\": \"Maximum height (m).\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Only use veg. class points?\",\n            \"flags\": [\"--only_use_veg\"],\n            \"description\": \"Only use veg. class points?\",\n            \"parameter_type\": \"Boolean\",\n            \"default_value\": \"false\",\n            \"optional\": true\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/install_wb_extension.json",
    "content": "{\n    \"tool_name\": \"InstallWbExtension\",\n    \"exe\": \"install_wb_extension\",\n    \"short_description\": \"Use to install a Whitebox extension product.\",\n    \"toolbox\": \"Whitebox Utilities\",\n    \"license\": \"Proprietary\",\n    \"example\": \">> .*EXE_NAME -r=LaunchWbRunner\",\n    \"parameters\": [\n        {\n            \"name\": \"Whitebox Extension Product Name\",\n            \"flags\": [\"--install_extension\"],\n            \"description\": \"Name of the extension product to install. Options include: 'General Toolset Extension', 'DEM & Spatial Hydrology Extension', 'Lidar & Remote Sensing Extension', and 'Agriculture Extension'\",\n            \"parameter_type\": {\"OptionList\": [\"General Toolset Extension\", \"DEM & Spatial Hydrology Extension\", \"Lidar & Remote Sensing Extension\", \"Agriculture Extension\"]},\n            \"default_value\": \"General Toolset Extension\",\n            \"optional\": false\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/launch_wb_runner.json",
    "content": "{\n    \"tool_name\": \"LaunchWbRunner\",\n    \"exe\": \"launch_wb_runner\",\n    \"short_description\": \"Opens the Whitebox Runner application.\",\n    \"toolbox\": \"Whitebox Utilities\",\n    \"license\": \"Proprietary\",\n    \"example\": \">> .*EXE_NAME -r=LaunchWbRunner\",\n    \"parameters\": [\n        {\n            \"name\": \"Clear the application state memory?\",\n            \"flags\": [\"--clear_app_state\"],\n            \"description\": \"Clear the application state memory?\",\n            \"parameter_type\": \"Boolean\",\n            \"default_value\": \"false\",\n            \"optional\": true\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/lidar_shift.json",
    "content": "{\n    \"tool_name\": \"LidarShift\",\n    \"exe\": \"lidar_shift\",\n    \"short_description\": \"Shifts the x,y,z coordinates of a LiDAR file.\",\n    \"toolbox\": \"LiDAR Tools\",\n    \"license\": \"Proprietary\",\n    \"example\": \">> .*EXE_NAME -r=LidarShift -i=input.las -o=output.las\",\n    \"parameters\": [\n        {\n            \"name\": \"Input LiDAR Points\",\n            \"flags\": [\"-i\", \"--input\"],\n            \"description\": \"Name of the input LiDAR points.\",\n            \"parameter_type\": {\"ExistingFile\":\"Lidar\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output LiDAR Points\",\n            \"flags\": [\"-o\", \"--output\"],\n            \"description\": \"Name of the output LiDAR points.\",\n            \"parameter_type\": {\"NewFile\":\"Lidar\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"x-shift\",\n            \"flags\": [\"-x\", \"--x_shift\"],\n            \"description\": \"x-shift value, blank for none.\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"y-shift\",\n            \"flags\": [\"-y\", \"--y_shift\"],\n            \"description\": \"y-shift value, blank for none.\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"z-shift\",\n            \"flags\": [\"-z\", \"--z_shift\"],\n            \"description\": \"z-shift value, blank for none.\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"\",\n            \"optional\": true\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/local_quadratic_regression.json",
    "content": "{\n    \"tool_name\": \"LocalQuadraticRegression\",\n    \"exe\": \"local_quadratic_regression\",\n    \"short_description\": \"An implementation of the constrained quadratic regression algorithm using a flexible window size described in Wood (1996).\",\n    \"toolbox\": \"Geomorphometric Analysis\",\n    \"license\": \"MIT\",\n    \"example\": \".*EXE_NAME -r=LocalQuadraticRegression --dem=DEM.tif --output=out_ras.tif --filter=15\",\n    \"parameters\": [\n        {\n            \"name\": \"Input DEM Raster\",\n            \"flags\": [\"-d\", \"--dem\"],\n            \"description\": \"Name of the input DEM raster file.\",\n            \"parameter_type\": {\"ExistingFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output Raster File\",\n            \"flags\": [\"-o\", \"--output\"],\n            \"description\": \"Name of the output raster file.\",\n            \"parameter_type\": {\"NewFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Filter Edge Length\",\n            \"flags\": [\"--filter\"],\n            \"description\": \"Edge length of the filter kernel.\",\n            \"parameter_type\": \"Integer\",\n            \"default_value\": \"3\",\n            \"optional\": true\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/max_upslope_value.json",
    "content": "{\n    \"tool_name\": \"MaxUpslopeValue\",\n    \"exe\": \"max_upslope_value\",\n    \"short_description\": \"Calculates the maximum upslope value from an input values raster along flowpaths.\",\n    \"toolbox\": \"Hydrological Analysis\",\n    \"license\": \"MIT\",\n    \"example\": \".*EXE_NAME -r=MaxUpslopeValue --dem=DEM.tif --values=values.tif --output=out.tif\",\n    \"parameters\": [\n        {\n            \"name\": \"Input DEM\",\n            \"flags\": [\"-d\", \"--dem\"],\n            \"description\": \"Input DEM; it must be depressionless.\",\n            \"parameter_type\": {\"ExistingFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Values Raster File\",\n            \"flags\": [\"--values\"],\n            \"description\": \"Name of the input values raster file.\",\n            \"parameter_type\": {\"ExistingFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output Raster File\",\n            \"flags\": [\"--output\"],\n            \"description\": \"Name of the output raster file.\",\n            \"parameter_type\": {\"NewFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/normalize_lidar.json",
    "content": "{\n    \"tool_name\": \"NormalizeLidar\",\n    \"exe\": \"normalize_lidar\",\n    \"short_description\": \"Normalizes a LiDAR point cloud.\",\n    \"toolbox\": \"LiDAR Tools\",\n    \"license\": \"Proprietary\",\n    \"example\": \">> .*EXE_NAME -r=NormalizeLidar -i=points.laz -o=normalized.laz --dtm=dtm.tif\",\n    \"parameters\": [\n        {\n            \"name\": \"Input LiDAR File\",\n            \"flags\": [\"-i\", \"--input\"],\n            \"description\": \"Name of the input LiDAR file.\",\n            \"parameter_type\": {\"ExistingFile\":\"Lidar\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output Lidar File\",\n            \"flags\": [\"-o\", \"--output\"],\n            \"description\": \"Name of the output LiDAR file.\",\n            \"parameter_type\": {\"NewFile\":\"Lidar\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Input DTM Raster File\",\n            \"flags\": [\"--dtm\"],\n            \"description\": \"Name of the input digital terrain model (DTM) raster file.\",\n            \"parameter_type\": {\"ExistingFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/qin_flow_accumulation.json",
    "content": "{\n    \"tool_name\": \"QinFlowAccumulation\",\n    \"exe\": \"qin_flow_accumulation\",\n    \"short_description\": \"Calculates Qin et al. (2007) flow accumulation.\",\n    \"toolbox\": \"Hydrological Analysis\",\n    \"license\": \"MIT\",\n    \"example\": \".*EXE_NAME -r=QinFlowAccumulation --dem=DEM.tif --output=QinMFD.tif --out_type='specific contributing area' --exponent=15.0 --max_slope=30.0 --threshold=10000\",\n    \"parameters\": [\n        {\n            \"name\": \"Input DEM Raster\",\n            \"flags\": [\"-d\", \"--dem\"],\n            \"description\": \"Name of the input DEM raster file; must be depressionless.\",\n            \"parameter_type\": {\"ExistingFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output Raster File\",\n            \"flags\": [\"--output\"],\n            \"description\": \"Name of the output raster file.\",\n            \"parameter_type\": {\"NewFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output Type\",\n            \"flags\": [\"--out_type\"],\n            \"description\": \"Output type; one of 'cells', 'specific contributing area' (default), and 'catchment area'.\",\n            \"parameter_type\": {\"OptionList\": [\"cells\", \"specific contributing area\", \"catchment area\"]},\n            \"default_value\": \"specific contributing area\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Upper-bound Exponent Parameter\",\n            \"flags\": [\"--exponent\"],\n            \"description\": \"Optional upper-bound exponent parameter; default is 10.0.\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"10.0\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Upper-bound Slope Parameter (in degrees)\",\n            \"flags\": [\"--max_slope\"],\n            \"description\": \"Optional upper-bound slope parameter, in degrees (0-90); default is 45.0.\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"45.0\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Convergence Threshold (grid cells; blank for none)\",\n            \"flags\": [\"--threshold\"],\n            \"description\": \"Optional convergence threshold parameter, in grid cells; default is infinity.\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": null,\n            \"optional\": true\n        },\n        {\n            \"name\": \"Log-transform the output?\",\n            \"flags\": [\"--log\"],\n            \"description\": \"Log-transform the output values?\",\n            \"parameter_type\": \"Boolean\",\n            \"default_value\": \"false\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Clip the upper tail by 1%?\",\n            \"flags\": [\"--clip\"],\n            \"description\": \"Optional flag to request clipping the display max by 1%.\",\n            \"parameter_type\": \"Boolean\",\n            \"default_value\": \"false\",\n            \"optional\": true\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/quinn_flow_accumulation.json",
    "content": "{\n    \"tool_name\": \"QuinnFlowAccumulation\",\n    \"exe\": \"quinn_flow_accumulation\",\n    \"short_description\": \"Calculates Quinn et al. (1995) flow accumulation.\",\n    \"toolbox\": \"Hydrological Analysis\",\n    \"license\": \"MIT\",\n    \"example\": \".*EXE_NAME -r=QuinnFlowAccumulation --dem=DEM.tif --output=QMFD.tif --out_type='specific contributing area' --exponent=1.1 --threshold=10000\",\n    \"parameters\": [\n        {\n            \"name\": \"Input DEM Raster\",\n            \"flags\": [\"-d\", \"--dem\"],\n            \"description\": \"Name of the input DEM raster file; must be depressionless.\",\n            \"parameter_type\": {\"ExistingFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output Raster File\",\n            \"flags\": [\"--output\"],\n            \"description\": \"Name of the output raster file.\",\n            \"parameter_type\": {\"NewFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output Type\",\n            \"flags\": [\"--out_type\"],\n            \"description\": \"Output type; one of 'cells', 'specific contributing area' (default), and 'catchment area'.\",\n            \"parameter_type\": {\"OptionList\": [\"cells\", \"specific contributing area\", \"catchment area\"]},\n            \"default_value\": \"specific contributing area\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Exponent Parameter\",\n            \"flags\": [\"--exponent\"],\n            \"description\": \"Optional exponent parameter; default is 1.0.\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"1.0\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Convergence Threshold (grid cells; blank for none)\",\n            \"flags\": [\"--threshold\"],\n            \"description\": \"Optional convergence threshold parameter, in grid cells; default is infinity.\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": null,\n            \"optional\": true\n        },\n        {\n            \"name\": \"Log-transform the output?\",\n            \"flags\": [\"--log\"],\n            \"description\": \"Log-transform the output values?\",\n            \"parameter_type\": \"Boolean\",\n            \"default_value\": \"false\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Clip the upper tail by 1%?\",\n            \"flags\": [\"--clip\"],\n            \"description\": \"Optional flag to request clipping the display max by 1%.\",\n            \"parameter_type\": \"Boolean\",\n            \"default_value\": \"false\",\n            \"optional\": true\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/raster_calculator.json",
    "content": "{\n    \"tool_name\": \"RasterCalculator\",\n    \"exe\": \"raster_calculator\",\n    \"short_description\": \"Performs a complex mathematical operations on one or more input raster images on a cell-to-cell basis.\",\n    \"toolbox\": \"Math and Stats Tools\",\n    \"license\": \"MIT\",\n    \"example\": \".*EXE_NAME -r=ConditionalEvaluation -i=DEM.tif --statement='value > 2500.0' --true=2500.0 --false=DEM.tif --output=onlyLowPlaces.tif\",\n    \"parameters\": [\n        {\n            \"name\": \"Statement:\",\n            \"flags\": [\"--statement\"],\n            \"description\": \"Statement e.g. cos(\\\"raster1\\\") * 35.0 + \\\"raster2\\\". This statement must be a valid Rust statement.\",\n            \"parameter_type\": \"String\",\n            \"default_value\": \"\",\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output Raster File\",\n            \"flags\": [\"--output\"],\n            \"description\": \"Name of the output raster file.\",\n            \"parameter_type\": {\"NewFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/repair_stream_vector_topology.json",
    "content": "{\n    \"tool_name\": \"RepairStreamVectorTopology\",\n    \"exe\": \"repair_stream_vector_topology\",\n    \"short_description\": \"This tool resolves topological errors and inconsistencies associated with digitized vector streams.\",\n    \"help\": \"This tool resolves topological errors and inconsistencies associated with digitized vector streams.\",\n    \"toolbox\": \"Stream Network Analysis\",\n    \"license\": \"MIT\",\n    \"example\": \">> .*EXE_NAME -r=RepairStreamVectorTopology --input=streams.shp --output=streams_fixed.shp --snap=2.0\",\n    \"parameters\": [\n        {\n            \"name\": \"Input Vector Lines\",\n            \"flags\": [\"-i\", \"--input\"],\n            \"description\": \"Name of the input lines vector file.\",\n            \"parameter_type\": {\"ExistingFile\":{\"Vector\":\"Line\"}},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output Lines\",\n            \"flags\": [\"-o\", \"--output\"],\n            \"description\": \"Name of the output lines vector file.\",\n            \"parameter_type\": {\"NewFile\":{\"Vector\":\"Line\"}},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Snap Distance\",\n            \"flags\": [\"--snap\", \"--dist\"],\n            \"description\": \"Snap distance, in xy units (metres).\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"\",\n            \"optional\": false\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/rho8_flow_accumulation.json",
    "content": "{\n    \"tool_name\": \"Rho8FlowAccumulation\",\n    \"exe\": \"rho8_flow_accumulation\",\n    \"short_description\": \"Calculates Fairfield and Leymarie (1991) flow accumulation.\",\n    \"toolbox\": \"Hydrological Analysis\",\n    \"license\": \"MIT\",\n    \"example\": \".*EXE_NAME -r=Rho8FlowAccumulation --dem=DEM.tif --output=Rho8.tif --out_type='specific contributing area'\",\n    \"parameters\": [\n        {\n            \"name\": \"Input DEM or Rho8 Pointer File\",\n            \"flags\": [\"-i\", \"--input\"],\n            \"description\": \"Input DEM or Rho8 pointer file; if a DEM is used, it must be depressionless.\",\n            \"parameter_type\": {\"ExistingFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output Raster File\",\n            \"flags\": [\"--output\"],\n            \"description\": \"Name of the output raster file.\",\n            \"parameter_type\": {\"NewFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output Type\",\n            \"flags\": [\"--out_type\"],\n            \"description\": \"Output type; one of 'cells', 'specific contributing area' (default), and 'catchment area'.\",\n            \"parameter_type\": {\"OptionList\": [\"cells\", \"specific contributing area\", \"catchment area\"]},\n            \"default_value\": \"specific contributing area\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Log-transform the output?\",\n            \"flags\": [\"--log\"],\n            \"description\": \"Log-transform the output values?\",\n            \"parameter_type\": \"Boolean\",\n            \"default_value\": \"false\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Clip the upper tail by 1%?\",\n            \"flags\": [\"--clip\"],\n            \"description\": \"Optional flag to request clipping the display max by 1%.\",\n            \"parameter_type\": \"Boolean\",\n            \"default_value\": \"false\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Is the input raster a Rho8 flow pointer?\",\n            \"flags\": [\"--pntr\"],\n            \"description\": \"Is the input raster a Rho8 flow pointer rather than a DEM?\",\n            \"parameter_type\": \"Boolean\",\n            \"default_value\": \"false\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"If a pointer is input, does it use the ESRI pointer scheme?\",\n            \"flags\": [\"--esri_pntr\"],\n            \"description\": \"Does the input Rho8 pointer use the ESRI style scheme?\",\n            \"parameter_type\": \"Boolean\",\n            \"default_value\": \"false\",\n            \"optional\": true\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/split_vector_lines.json",
    "content": "{\n    \"tool_name\": \"SplitVectorLines\",\n    \"exe\": \"split_vector_lines\",\n    \"short_description\": \"Used to split a vector line coverage into even-lengthed segments.\",\n    \"toolbox\": \"GIS Analysis\",\n    \"license\": \"MIT\",\n    \"example\": \">> .*EXE_NAME -r=SplitVectorLines -i=input.shp -o=line_segments.shp --length=100.0\",\n    \"parameters\": [\n        {\n            \"name\": \"Input Lines\",\n            \"flags\": [\"-i\", \"--input\"],\n            \"description\": \"Name of the input lines shapefile.\",\n            \"parameter_type\": {\"ExistingFile\":{\"Vector\":\"Line\"}},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output Lines\",\n            \"flags\": [\"-o\", \"--output\"],\n            \"description\": \"Name of the output lines shapefile.\",\n            \"parameter_type\": {\"NewFile\":{\"Vector\":\"Line\"}},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Max Segment Length\",\n            \"flags\": [\"--length\"],\n            \"description\": \"Maximum segment length (m).\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": null,\n            \"optional\": true\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/travelling_salesman_problem.json",
    "content": "{\n    \"tool_name\": \"TravellingSalesmanProblem\",\n    \"exe\": \"travelling_salesman_problem\",\n    \"short_description\": \"Finds approximate solutions to travelling salesman problems, the goal of which is to identify the shortest route connecting a set of locations.\",\n    \"toolbox\": \"GIS Analysis\",\n    \"license\": \"MIT\",\n    \"example\": \">> .*EXE_NAME -r=TravellingSalesmanProblem -i=input.shp -o=route.shp --duration=120\",\n    \"parameters\": [\n        {\n            \"name\": \"Input Points\",\n            \"flags\": [\"-i\", \"--input\"],\n            \"description\": \"Name of the input points shapefile.\",\n            \"parameter_type\": {\"ExistingFile\":{\"Vector\":\"Point\"}},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output Lines\",\n            \"flags\": [\"-o\", \"--output\"],\n            \"description\": \"Name of the output lines shapefile.\",\n            \"parameter_type\": {\"NewFile\":{\"Vector\":\"Line\"}},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Max Duration\",\n            \"flags\": [\"--duration\"],\n            \"description\": \"Maximum duration, in seconds.\",\n            \"parameter_type\": \"Integer\",\n            \"default_value\": \"60\",\n            \"optional\": false\n        }\n    ]\n}"
  },
  {
    "path": "WBT/plugins/vector_stream_network_analysis.json",
    "content": "{\n    \"tool_name\": \"VectorStreamNetworkAnalysis\",\n    \"exe\": \"vector_stream_network_analysis\",\n    \"short_description\": \"This tool performs common stream network analysis operations on an input vector stream file.\",\n    \"help\": \"This tool performs common stream network analysis operations on an input vector stream file.\",\n    \"toolbox\": \"Stream Network Analysis\",\n    \"license\": \"MIT\",\n    \"example\": \">> .*EXE_NAME -r=VectorStreamNetworkAnalysis --streams=rivers.shp --dem=DEM.tif -o=network_analysis.shp --cutting_height=10.0 --snap=1.0\",\n    \"parameters\": [\n        {\n            \"name\": \"Input Streams Vector\",\n            \"flags\": [\"--streams\"],\n            \"description\": \"Name of the input streams vector file.\",\n            \"parameter_type\": {\"ExistingFile\":{\"Vector\":\"Line\"}},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Input DEM Raster\",\n            \"flags\": [\"--dem\"],\n            \"description\": \"Name of the input DEM raster file.\",\n            \"parameter_type\": {\"ExistingFile\":\"Raster\"},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Output Lines\",\n            \"flags\": [\"-o\", \"--output\"],\n            \"description\": \"Name of the output lines shapefile.\",\n            \"parameter_type\": {\"NewFile\":{\"Vector\":\"Line\"}},\n            \"default_value\": null,\n            \"optional\": false\n        },\n        {\n            \"name\": \"Maximum Ridge-cutting Height (z units)\",\n            \"flags\": [\"--cutting_height\"],\n            \"description\": \"Maximum ridge-cutting height (z units).\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"10.0\",\n            \"optional\": true\n        },\n        {\n            \"name\": \"Snap Distance\",\n            \"flags\": [\"--snap\"],\n            \"description\": \"Snap distance, in xy units (metres).\",\n            \"parameter_type\": \"Float\",\n            \"default_value\": \"0.1\",\n            \"optional\": true\n        }\n    ]\n}"
  },
  {
    "path": "WBT/readme.txt",
    "content": "WhiteboxTools\n\nThe main tool library is contained in the whitebox_tools (or whitebox_tools.exe on \nMS Windows) file. This is a command-line program that can be run from a terminal, i.e. \ncommand prompt. For details on usage, change the working directory (cd) to this folder \nand type the following at the command prompt:\n\n./whitebox_tools --help\n\nThe following commands are recognized:\n--cd, --wd       Changes the working directory; used in conjunction with --run flag.\n-h, --help       Prints help information.\n-l, --license    Prints the whitebox-tools license.\n--listtools      Lists all available tools. Keywords may also be used, --listtools slope.\n-r, --run        Runs a tool; used in conjunction with --wd flag; -r=\"LidarInfo\".\n--toolbox        Prints the toolbox associated with a tool; --toolbox=Slope.\n--toolhelp       Prints the help associated with a tool; --toolhelp=\"LidarInfo\".\n--toolparameters Prints the parameters (in json form) for a specific tool; --toolparameters=\"LidarInfo\".\n-v               Verbose mode. Without this flag, tool outputs will not be printed.\n--viewcode       Opens the source code of a tool in a web browser; --viewcode=\"LidarInfo\".\n--version        Prints the version information.\n\nExample Usage:\n>> ./whitebox-tools -r=lidar_info --cd=\"/path/to/data/\" -i=input.las --vlr --geokeys\n\n\nThe WhiteboxTools library may also be called from Python automation scripts. The \nwhitebox_tools.py script can be used as an easy way of interfacing with the various \ncommands. See the user manual for more deails. To use this script, simply use the \nfollowing import:\n\nfrom whitebox_tools import WhiteboxTools\n\nwbt = WhiteboxTools() \nwbt.work_dir = \"/path/to/data/\" # Sets the Whitebox working directory\n\nwbt.d_inf_flow_accumulation(\"DEM.dep\", \"output.dep\", log=True)\n\n\nAdditionally, included in this directory is the WhiteboxTools Runner, a simple Tkinter \nuser-interface that allows users to run the WhiteboxTools tools, with convenience for \nspecifying tool parameters. To run this interface, simply type:\n\npython3 wb_runner.py\n\nOr, if Python 3 is the default Python interpreter:\n\npython wb_runner.py\n\nAt the command prompt (after cd'ing to this folder, which contains the script).\n\nWhiteboxTools is distributed under a permissive MIT open-source license. See LICENSE.txt \nfor more details.\n\n******************\n* Release Notes: *\n******************\n\nVersion 2.3.0 (30-03-2023)\n- Added the new Whitebox Runner v2.0. This version of WbRunner is an entirely new application with many \n  advancements over the previous version of the WbRunner. It is now written in pure Rust (compared with \n  the old Python TkInter app) using the egui user-interface library. It has a more modern feel, is \n  cross-platform, and has no dependencies (including Python). You can now open multiple tools simultaneously. \n- WbRunner is now the preferred way now for installing the Whitebox Toolset Extension (WTE).\n- Added the LaunchWbRunner and InstallWbExtension tools so that the Whitebox Runner will be more \n  accessible from other Whitebox frontends. This way users will always have a good fall-back if the \n  frontend is not up-to-date with the WBT backend, since WbRunner is always current with the installed \n  version of WBT.\n- Added the IndividualTreeDetection tool for identifying points in a LiDAR point cloud that are associated \n  with the tops of individual trees.\n- Added the NormalizeLidar tool for normalizing LiDAR point clouds, i.e., converting their z-values \n  from elevation to height-above-ground.\n- Natural Resources Canada (NRCan) has sponsored the open-sourcing of two tools contained in the extension,\n  VectorStreamNetworkAnalysis and RepairStreamVectorTopology. These two tools are are now available in the \n  WbT Open Core.\n- Fixed a bug with the LidarShift tool. The tool was calculating the shift in transformed coordinates\n  incorrectly leading to very strange outputs.\n- The MultiscaleTopographicPositionImage tool now takes an optional hillshade image as input.\n- Lowered the peak memory requirement of the D8FlowAccumulation tool.\n- Fixed a bug with the location of the settings.json file when running plugin tools, that sometimes\n  led to the file being located in a top-level directory, and therefore sometimes yielding a \n  permissions error when running on systems without admin rights.\n- Fixed a bug with the vector attribute table reader that caused issue with the VectorPolygonsToRaster \n  tool.\n- Fixed a bugs in the HorizonAngle and ExposureTowardsWindFlux tools.\n- Added a point time interpolation parameter to the LidarNearestNeighbourGridding tool.\n- Added the ListUniqueValuesRaster tool.\n- Fixed a bug with the SetNodataValue tool, where the raster data type is updated to a signed integer\n  if the background value is negative and the input image has an unsigned data type.\n- Added a 'mean' option to the VectorPointsToRaster tool.\n\nVersion 2.2.0 (23-10-2022)\n- Added the TravellingSalesmanProblem tool for identifying short routes connecting multiple locations.\n- Added the HeatMap tool for performing kernel density estimation (KDE) from vector points.\n- Added the MultiplyOverlay tool.\n- Added the MaxUpslopeValue tool.\n- Added the ConditionedLatinHypercube tool for stratified random sampling (credit Dr. Dan Newman).\n- Added the HighPassBilateralFilter tool, useful for emphasizing image texture.\n- Fixed a bug with the DirectDecorrelationStretch tool.\n- Fixed a bug in the automatic install of the Whitebox extensions that affected Windows users.\n- Fixed a bug with the persistence of the compress_rasters parameter. Python users were unable to\n  turn off the compress flag previously.\n- Added the option to set and get the maximum number of processors (--max_procs flag) used by WBT in \n  the Whitebox Python API.\n- Added the option to output average point density and nominal point spacing to the LidarInfo tool.\n- Updated the ClassifyOverlapPoints and FlightlineOverlap tools to use information contained within\n  the Point Source ID property, rather than a hard-coded time difference threshold previously used.\n- Fixed an issue that affected many tools when input rasters use either NaN or Inf as NoData values.\n- Fixed an issue with the way that NoData values are handled during the euclidean distance transform\n  that impacted the EuclideanDistance, EuclideanAllocation, BufferRaster, and \n  ElevationAboveStreamEuclidean tools.\n- Fixed a bug with the LidarInfo tool that occurred when the user did not specify the mandatory \n  output parameter along with a non LAS input file.\n- Fixed a bug with the Truncate tool; the output image was always integer, and therefore it did not\n  work as expected when using more than zero significant digits.\n- Fixed a bug with the ConstructVectorTIN tool that resulted in an error when no field data are used.\n- Modified the code for writing to the settings.json file so that rather than issuing an error when\n  the app doesn't have write permission, it simply prints a warning and carries on.\n- Fixed bugs in the Geomorphons tool (submitted by Dr. Dan Newman).\n- Fixed a bug with the writing of PolyLineZ vectors.\n- Updated the Hillshade, MultidirectionalHillshade, and RelativeAspect tools to use the more robust \n  5x5 3rd order bivariate polynomial method of Florinsky (2016) for rectangular grid DEMs, and the \n  3x3 method, also described by Florinsky (2016), for DEMs in geographic coordinates. This is a large \n  improvement in accuracy for calculating these surface morphology parameters on geographic coordinates\n  compared with the 'z-conversion fudge factor' method used previously.\n- Added support for Apple Silicon; you can now download WhiteboxTools binaries compiled on an M1 Mac.\n\nVersion 2.1.0 (30-01-2022)\n- The Geomorphons tool for landform classification is now available.\n- Added the MeanCurvature, GaussianCurvature, MinimalCurvature and MaximalCurvature tools.\n- Added GaussianScaleSpace tool, which uses the fast Gaussian approximation algorithm to produce \n  scaled land-surface parameter measurements from an input DEM.\n- Added LocalQuadraticRegression tool, which is an implementation of the constrained quadratic \n  regression algorithm using a flexible window size described in Wood (1996).\n- Added the MaxUpslopeElevChange tool, the upslope equivalent of the MaxDownslopeElevChange tool.\n- Updated the Slope, Aspect, ProfileCurvature, TangentialCurvature, PlanCurvature, and\n  TotalCurvature tools to use the more robust 5x5 3rd order bivariate polynomial method\n  of Florinsky (2016) for rectangular grid DEMs, and the 3x3 method, also described by\n  Florinsky (2016), for DEMs in geographic coordinates. This is a large improvement in\n  accuracy for calculating these surface morphology parameters on geographic coordinates\n  compared with the 'z-conversion fudge factor' method used previously.\n- Added the LidarShift tool for applying a simple shift to point x,y,z coordinates.\n- Added the ability to automatically install the Whitebox extensions using the Python API.\n- Fixed a bug in the lower quartile valley mapping method of the ExtractValleys tool.\n- Fixed a bug in the PennockLandformClass tool.\n- Fixed a bug in the Shapefile reader that affected files of the PointZ ShapeType.\n- Fixed a bug with the CsvPointsToVector tool.\n- Reduced the peak memory usage of the D8Pointer and Rho8Pointer tools by about 37.5%.\n- Several other minor bugs have been fixed.\n\nVersion 2.0.0 (30-08-2021)\n- The most important feature in this release is the addition of support for reading and writing the LAZ\n  compressed LiDAR format for all of the LiDAR tools in WBT.\n- Added the RasterCalculator tool for performing complex mathematical operations on input rasters.\n- Added the ConditionalEvaluation tool for performing an if-then-else operation on an input raster.\n- Added the EdgeContamination tool to identify grid cells for which the upslope area extends beyond\n  the data extent.\n- Added the ExposureTowardsWind tool.\n- Added the QuinnFlowAccumulation tool to perform a Quinn et al. (1995) flow accumulation operation.\n- Added the QinFlowAccumulation tool to perform a Qin et al. (2007) flow accumulation operation.\n- Added the Rho8FlowAccumulation tool to perform a Fairfield and Leymarie (1991) flow accumulation \n  operation.\n- LidarHistogram now allows a GPS time parameter, which can be useful for determining the number of\n  flightlines in a LiDAR tile.\n- Fixed a bug with the Resample tool that created an artifact when reampling to resolutions less than \n  one meter.\n- Fixed a bug that prevented plugin tools from being discovered by the open-core when run from the command\n  line on PATH when the working directory was something other than WBT.\n- Fixed several bugs in the ContoursFromPoints tool.\n- Fixed the z_factor calculation for large-extent DEMs in geographic coordinates for the geomorphometric\n  shape metric tools, e.g. slope, aspect, hillshade, and curvatures. The new approach calculates a different\n  z_factor conversion value for each row in the raster, rather than using a single value based on the raster \n  mid-point latitude. This should help improve the accuracy of these shape indices on large-extent rasters \n  in geographic coordinate systems.\n- Fixed several bugs in the isobasins and D8 flow accumulation tool.\n- The NewRasterFromBase tool now accepts a vector base file (and grid cell size) as well as a raster.\n- The WhiteboxTools user manual has had a refresh and is now hosted at: \n  https://www.whiteboxgeo.com/manual/wbt_book/intro.html\n- We have added numerous tools to the WhiteboxTools Extensions. For details see:\n  https://www.whiteboxgeo.com/whitebox-geospatial-extensions/\n\nVersion 1.5.0 (31-05-2021)\n- This release does not include very many new tools. Despite this, this is probably one of the largest \n  releases yet. We have made extensive changes to the codebase, improving functionality in many \n  significant ways. Therefore, we're very excited to announce the release of v1.5.\n- Probably the most exciting change is the introduction of plugin tools. Up until now, WBT has had a \n  monolithic architecture, where all of the tools live within a single binary. This architecture has \n  provided a number of benefits up until now. However, as the number of tools in WBT grows, it becomes\n  increasingly difficult to maintain this program structure - in particular, compile times have grown\n  significantly since the projects start. A plugin architecture provides much greater flexibility in \n  this regard. Single tool plugins can be created, placed within the new 'plugins' folder within the \n  WBT directory, and the whitebox_tools.exe binary will treat these plugins like any other tool within\n  the monolith. This also means that WBT users can develop their own custom tools, without the required \n  know-how of figuring out how to integrate their tool into the large WBT code-base. The user manual\n  will be updated shortly to describe how this process works. For now, there is only one plugin tool \n  example in the open-core (SplitVectorLines) although several other plugins have been developed (more \n  on this below). The one downside of the new plugin architecture is that the size of the WBT download\n  will inevitably grow, as individual tool executables will be larger than the single monolith. We \n  believe that this is an acceptable compromise. \n- In order to accommodate plugin tools, we have significantly changed the codebase. Most significantly \n  We have pulled the code associated with low-level functions, the so-called 'plumbing' code, (e.g. \n  code for reading and writing various data files) into separate sub-repositories. In this way, the \n  tools in the monolith and the plugin tools can both use this code without duplication.\n- WBT now has persistent environment variables contained within a 'settings.json' file within the WBT \n  folder. Currently, these settings including 'verbose_mode', 'working_directory', 'compress_rasters', \n  and 'max_procs'. More environment variables may be added in later releases. The fact that verbose mode\n  the working directory, and the compress_rasters flag are now persistent does have implications for the\n  Python and R front-ends and for the way these settings are used. The user manual will be updated \n  shortly to reflect these changes.\n- We introduced the 'max_procs' setting. Now, all tools that run in parallel, or partially parallelize,\n  can be restricted to a maximum number of processes. Before, WBT would simply use all of the available\n  cores in the machine it was running on. While this is still the default (`max_procs: -1`), there are\n  certain conditions where this behaviour is undesirable. For example, when WBT is run on large servers \n  or cloud-computing environments where a great many cores are shared among many users, it can be \n  problematic when a single user/program consumes all of the available cores. This setting limits \n  the maximum number of procs.\n- Added the EmbankmentMapping tool for mapping transportation embankments (road, rail) in LiDAR DEMs.\n- Added the SplitVectorLines tool. This tool will parse an input line vector into a series of segments\n  of a specified length. It is also an example of a WBT plugin.\n- The code has been updated to reflect the new zLidar v1.1 specification, which has significantly improved \n  compression rates (testing shows it is between 91% and 109% of LAZ), greater flexibility (users may\n  specify the degree of compression versus speed of reading/writing), and numerous bug fixes. The zLidar \n  specification webpage will soon be updated to reflect the new version. Further news on this front, \n  it has come to our attention recently that there is now a Rust-based LAZ encoder/decoder, which provides \n  an opportunity for us to add LAZ support in a future version of WBT. We are currently evaluating this\n  as an option.\n- We are trying to be more engaging with the WBT user community. In this regard, we have set up a new\n  Google Groups forum for user to ask questions (https://groups.google.com/g/whiteboxtools), and have a \n  new Twitter account (@whiteboxgeo) and newsletter to make announcements. Feel free to sign up for \n  either if you're interested in staying in touch. \n- Lastly, we are very pleased to announce the creation of WhiteboxTools Geospatial Inc., a new company \n  based on providing extension services around the open-source WBT platform. It is our vision that this\n  company will provide a way of making the ongoing development of the WBT open-core more sustainable in \n  the future, by enabling developers to work full-time on the project. Please read my 'open letter to the \n  WBT community' (https://www.whiteboxgeo.com/open-letter-whiteboxtools-community/) for more details \n  about this exciting development. Our plan is to maintain, and continue development of, the open-core of \n  WBT, while providing plugin extensions that enhance the core capabilities. To begin with, we are launching\n  the Whitebox General Toolset Extension, a set of (currently) 19 tools to help GIS professionals with their\n  everyday workflows. Please see the newly redesigned WBT webpage at www.whiteboxgeo.com for more details.\n  If you have been interested in supporting the WBT project in the past and haven't known how, buying a \n  license for the General Toolset Extension is a wonderful way of doing so.\n\nVersion 1.4.0 (04-09-2020)\n- Added the TimeInDaylight model tool for modelling the proportion of daytime that a location is not in shadow.\n- Added the MapOffTerrainObjects tool.\n- Added the FilterRasterFeaturesByArea tool.\n- Added the LidarDigitalSurfaceModel tool.\n- The D8 and FD8 flow pointer tools now output byte rasters.\n- The Isobasins tool now optionally outputs an upstream/downstream connections table.\n- The HorizonAngle tool has had significant performance improvements.\n- Improvements to the RemoveOffTerrainObjects tool's performance.\n- The Resample tool has been modified so that it does not require a 'destination' raster. Instead,\n  it will create a new output raster either based on a user-specified target cell resolution or\n  an optional base raster, much like the vector-to-raster conversion tools.\n- Tools that input a z_factor conversion no longer override user input with geographic coordinates\n  (see issue #113).\n- The StreamLinkIdentifier tool now outputs a 32-bit integer format, increasing the maximum allowable \n  number of streams (see issue #110).\n- Fixed a bug with cubic-convolution and bilinear resampling in the Mosaic tool (see issue #109).\n\nVersion 1.3.1 (23-07-2020)\n- Added the HypsometricallyTintedHillshade tool to create hypsometric tinted hillshades.\n- Added the MultidirectionalHillshade tool.\n- Added the ability to read/write in the Esri BIL raster format.\n- Added the LidarRooftopAnalysis tool.\n- The MultiPartToSinglePart tool now handles MultiPoint vectors.\n- Fixed a bug with the VoronoiDiagram to better handle MultiPoint vectors.\n- Fixed an issue with writing compressed RGB GeoTIFFs.\n- Fixed an issue reading LZW compressed GeoTIFFs.\n\nVersion 1.3.0 (07-06-2020)\n- Tools will now output DEFLATE compressed GeoTIFFs when the --compress_rasters parameter is used.\n- Added support for a newly developed compressed LiDAR data format, the ZLidar file. All tools\n  that accepted LAS file inputs and produced LAS outputs can now use '*.zlidar' files as well. I \n  have also added the LasToZlidar and ZlidarToLas tools to perform conversions. While the ZLidar\n  format does not yield compression rates quite as good as the popular LAZ file format, you can  \n  expect ZLidar files to be between 20-30% of the size of the equivalent LAS file. A file  \n  specification will be published in the near future to describe the open ZLidar data format.\n- Added the AsciiToLas tool.\n- Added the ContoursFromRaster tool for creating a vector contour coverage from a raster surface model (DEM).\n- Added the ContoursFromPoints tool for creating a vector contour coverage from vector points.\n- Added the UpdateNodataCells tool.\n- Modified the Slope tool to optionally output in degrees, radians, or percent gradient.\n- Modified the Mosaic tool, which now runs much faster with large numbers of input tiles.\n- The vector-to-raster conversion tools now preserve input projections.\n- Fixed a bug in the RasterToVectorPolygons tool.\n- Fixed several bugs in the MergeTableWithCsv tool.\n- Modified the FillMissingData tool to allow for the exclusion of edge-connected NoData cells from the operation.\n  This is better for irregular shaped DEMs that have large areas of NoData surrounding the valid data.\n- The LidarConstructVectorTin tool has been depreciated. The tool was not creating the proper output.\n  Furthermore, since the number of points in the average LiDAR tile is usually many million, this tool\n  would usually produce Shapefiles that exceed the maximum allowable number of shape geometries. If \n  a vector TIN is required for a LiDAR point set, users should convert the file to a Shapefile and then\n  use the ConstructVectorTin tool instead. And of course, if you are interested in a raster TIN from a \n  LiDAR file, use the LidarTinGridding tool instead. \n- FlattenLakes now handles multipart lake polygons.\n\nVersion 1.2.0 (21-02-2020)\n- Added the RasterToVectorPolygons tool, which now completes the raster-vector conversion tool set.\n- Added the MultiscaleElevationPercentile tool.\n- Added the AttributeCorrelationNeighbourhoodAnalysis tool.\n- Added the RadialBasisFunctionInterpolation tool, which includes a thin-plate spline mode.\n- Added the RasterPerimeter tool to measure the perimeter of raster polygons.\n- Added the MDInfFlowAccumulation tool to perform the MD-infinity flow accumulation of Seibert \n  and McGlynn (2007).\n- Added the InsertDams tool, which can be used to insert impoundment features at a set of points\n  of interest into a DEM. This tool can be used in combination with the ImpoundmentSizeIndex tool \n  to create artificial reservoirs/depressions.\n- Added the HeightAboveGround tool, to normalize a LiDAR point cloud. Each point's z-value is\n  converted to the height above the nearest ground-classified point.\n- Modified the LidarRbfInterpolation tool to improve efficiency.\n- Fixed an issue with how floating point attributes were written in Shapefile attribute tables.\n- Updated the LidarSegmentation tool, which now used RANSAC to fit planar models to points.\n- Fixed an issue with the Reclass and ReclassFromFile tool that caused striping.\n- The Relcass and ReclassFromFile tools now take 'min' and 'max' in the reclass string.\n- The watershed tool now accepts either a set of vector points or a raster for the pour points \n  file. If a raster is specified, all non-zero, non-NoData valued cells will be considered \n  outlet cells and the watershed labels will be assigned based on these values.\n- The D8 and D-infinity flow accumulation tools now take either an input DEM or a flow pointer raster \n  as inputs.\n\nVersion 1.1.0 (09-12-2019)\n- Added the BreachDepressionsLeastCost tool, which performs a modified form of the Lindsay \n  and Dhun (2015) impact minimizing breaching algorithm. This modified algorithm is very \n  efficient and can provide an excellent method for creating depressionless DEMs from large \n  DEMs, including those derived from LiDAR. It is particularly well suited to breaching \n  through road embankments, approximately the pathway of culverts.\n- The FillDepressions tool algorithm has been completely re-developed. The new algorithm is\n  significantly faster than the previous method, which was based on the Wang and Lui method.\n  For legacy reasons, the previous tool has been retained and renamed FillDepressonsWangAndLui.\n  Notice that this new method also incorporates significantly improved flat area correction\n  that maintains general flowpaths of filled areas.\n- The Sink and DepthInSink tools have been updated to use the new depression filling algorithm.\n- Added the ClassifyBuildingsInLidar tool to reclassify LiDAR points within a LAS file\n  to the building class value (6) that are located within one or more building footprint\n  contained in an input polygon vector file. \n- Added the NaturalNeighbourInterpolation tool for performing Sibson's (1981) interpolation\n  method on input point data.\n- Added the UpslopeDepressionStorage tool to estimate the average upslope depression \n  storage capacity (DSC).\n- Added the LidarRbfInterpolation tool for performing a radial basis function (RBF) interpolation\n  of LiDAR data sets.\n- The WhiteboxTools Runner user interface has been significantly improved (many thanks to \n  Rachel Broders for these contributions).\n- Fixed a bug in which the photometric interpretation was not being set by certain raster\n  decoders, including the SAGA encoder. This was causing an error when outputting GeoTIFF \n  files.\n- Updated the ConstructVectorTIN and TINGridding tools to include a maximum triangle edge \n  length to help avoid the creation of spurious long and narrow triangles in convex regions \n  along the data boundaries.\n- Added the ImageCorrelationNeighbourhoodAnalysis tool for performing correlation analysis\n  between two input rasters within roving search windows. The tool can be used to perform\n  Pearson's r, Spearman's Rho, or Kendall's Tau-b correlations.\n\nVersion 1.0.2 (01-11-2019)\n- Added the BurnStreamsAtRoads tool.\n- Added a two-sample K-S test (TwoSampleKsTest) for comparing the distributions of two rasters.\n- Added a Wilcoxon Signed-Rank test (WilcoxonSignedRankTest) for comparing two rasters.\n- Added a paired-samples Student's t-test (PairedSampleTTest) for comparing two rasters.\n- Added the inverse hyperbolic trig functions, i.e. the Arcosh, Arsinh, and Artanh tools.\n- Renamed the LeeFilter to the LeeSigmaFilter.\n- Renamed the RelativeStreamPowerIndex tool to StreamPowerIndex, to be more in-line with\n  other software.\n- Fixed another bug related to the handling of Boolean tool parameters.\n\nVersion 1.0.1 (20-10-2019)\n- Boolean type tool parameters previously worked simply by the presence of the parameter flag.\n  This was causing problems with some WBT front-ends, particularly QGIS, where the parameters\n  were being provided to WBT as --flag=False. In this case, because the flag was present, it \n  was assumed to be True. All tools that have boolean parameters have been updated to handle\n  the case of --flag=False. This is a widespread modification that should fix the unexpected\n  behaviour of many tools in certain front-ends.\n- Fixed a minor bug with the VectorPolygonToRaster tool.\n- Fixed a bug in the DownstreamDistanceToStream tool.\n\nVersion 1.0.0 (29-09-2019)\n- Added support for reading and writing the BigTIFF format. This has resulted in numerous changes\n  throughout the codebase as a result of significant modification of ByteOrderReader and addition\n  of ByteOrderWriter. This change has touched almost every one of the raster format \n  encoders/decoders.\n- Performance improvements have been made to the FlattenLakes (hydro-flattening) tool.\n- Fixed a bug preventing the SplitColourComposite tool from reading the '--input' flag correctly.\n- The ClipLidarToPolygon now issues a warning if the output LAS file does not contain any points\n  within the clipped region and does not output a file. Also, the LAS reader no longer panics \n  when it encounters a file with no points. Now it reads the header file, issues a warning, and \n  carries on, allowing the tools to handle the case of no points.\n- ImageRegression can now optionally output a scatterplot. The scatterplot is based on a random \n  sample of a user-defined size.\n- Added the CleanVector tool.\n- ExtractRasterStatistics has been renamed ZonalStatistics to be more inline with other GIS, \n  including ArcGIS and QGIS.\n- Added the median as a statistic that ZonalStatistics provides.\n- Fixed a bug in the VectorPolygonsToRaster tool that sometimes mishandled polygon holes.\n- Added the FilterLidarClasses tool to filter out points of user-specified classes.\n- Added the LidarRansacPlanes tool to identify points belonging to planar surfaces. This tool\n  uses the RANSAC method, which is a robust modelling method that handles the presence of \n  numerous outlier points.\n- The ClipLidarToPolygon tool has been parallelized.\n- The LasToAscii and AsciiToLas tools have been updated to handle RGB colour data for points.\n- Added the CsvPointsToVector tool to convert a CSV text table into a shapefile of vector points. \n  The table must contain x and y coordinate fields.\n- The FeaturePreservingDenoise was renamed to FeaturePreservingSmoothing. The DrainagePreservingSmoothing\n  tool was removed. Use FeaturePreservingSmoothing instead.\n- Added the ability to output the average number of point returns per pulse in the LidarPointStats tool.\n- LidarTinGridding, LidarIdwIntarpolation, and LidarNearestNeighbourGridding now can interpolate the \n  return number, number of returns, and RGB colour data associated with points in a LAS file.\n- Added the ModifyNoDataValue tool to change the NoData value in a raster. It updates the value in \n  the raster header and then modifies each grid cell in the raster containing the old NoData value\n  to the new value. This operation overwrites the existing raster.\n- Fixed an issue with GeoTIFF NoData values that impacted many tools. NoData values were not interpreted\n  correctly when they were very large positive or negative values (near the min/max of an f32).\n\nVersion 0.16.0 (24-05-2019)\n- Added the MergeLineSegments and SphericalStdDevOfNormals tools.\n- Fixed a bug with reading LAS files with point records with extra bytes. Previously, the LAS decoder\n  assumed the Point Record Length matched that of the LAS specifications (with the variable of the \n  optional intensity and user data). Some LAS files in the wild (particularly those created using \n  LASTools and of LAS version 1.2) have larger Point Record Lengths, which presumably carry extra \n  bytes of information. These extra byes are ignored, but they no longer throw off the decoding.\n- Fixed a bug with writing Big-Ending GeoTIFF files. The 'MM' file header was not correct previously.\n- Significantly reduced the memory requirements of the StochasticDepressionAnalysis tool. The tool \n  may be somewhat slower as a result, but it should be applicable to larger DEMs than was previously\n  possible.\n- Fixed bugs with the Union and SplitWithLines tools. \n- WhiteboxTools can now read and write Shapefiles of MultiPointZ, PolyLineZ, and PolygonZ ShapeTypes \n  missing the optional 'M' values (i.e. measures).\n- SelectTilesByPolygon and LidarTileFootprint are now compatible with LAZ file inputs. Both of these \n  tools only rely on information in the input LiDAR file's header, which is the same for a LAZ file \n  as a LAS file.\n- Fixed a bug with writing Saga GIS files (*.sdat) that inverted rasters.\n\nVersion 0.15.0 (03-03-2019)\n- The following tools were added to the project:\n  BoundaryShapeComplexity\n  NarrownessIndex\n  ShapeComplexityIndexRaster\n\n- Fixed a bug with the PanchromaticSharpening tool.\n- Previously, if a LAS v1.4 file were input to a tool, the output LAS file, which is currently\n  always in LAS v1.3 format, would not correctly translate the 64-bit information (point \n  return, number of returns, classification) into 32-bit format. I have added the \n  get_32bit_from_64bit function to handle this translation more gracefully; albeit it is\n  still a lossy translation where returns greater than 5 are ignored and classification \n  values greater than 31 are lost. \n- Added a maximum triangle edge length parameter to the LidarTinGridding tool to allow \n  for the exclusion of large-area triangles (i.e. low point density) from the gridding.\n- The NormalizedDifferenceVegetationIndex tool has been renamed to NormalizedDifferenceIndex \n  to indicate the more general nature of this tool (i.e. NDVI, NDWI, OSAVI, etc.).\n- Significant changes have been made to the BreachDepressions tool to make it more in-line\n  with the behaviour of the GoSpatial algorithm described in the original Lindsay (2016)\n  paper. These changes include: 1) the inclusion of an optional parameter to fill single-cell\n  pits prior to breaching, 2) the addition of a --flat_increment parameter, which overrides\n  the automatically derived value assigned to flat areas along breach channels (or filled \n  depressions), and 3) the tool now performs a fast post-breach filling operation, when\n  run in constrained-breaching mode (i.e. when the user specifies values for either \n  --max_depth or --max_length, placing constraints on the allowable breach channel size).\n\nVersion 0.14.1 (10-02-2019)\n- This release largely focuses on bug-fixes rather than feature additions. However, the\n  following tools were added to the library:\n  RasterArea\n  \n- Fixed a bug with the MultiscaleTopographicPositionImage tool that prevented proper output\n  for files in GeoTIFF format. \n- Several other tool-specific bug fixes.\n\nVersion 0.14.0 (27-01-2019)\n- The release largely focuses on bug-fixes rather than adding new features. The\n following tools were added to the project:\n    CircularVarianceOfAspect\n    EdgeDensity\n    SurfaceAreaRatio\n\n- Fixed a bug that resulted in rasters with projected coordinate systems being\n  interpreted as geographic coordinates, thereby messing up the calculation of \n  inter-cell distances for tools like slope, aspect, curvature, etc.\n- Fixed a bug with several of the math tools; output files took their data type\n  from the input file. In some cases, this does not work well because the input\n  is integer and the output must be floating point data.\n\n\nVersion 0.13.0 (08-01-2019)\n- The release largely focuses on bug-fixes rather than adding new features. The\n following tools were added to the project:\n    MosaicWithFeathering\n- Support was added for GeoTIFF MODELTRANSFORMATIONTAG (Tag 33920).\n- Support was added for reading GeoTIFFs that have coordinate transformations \n  defined by multiple tiepoints contained with the ModelTiepointTag (Tag 33922).\n  These rasters have their raster-to-model transform defined by a 2D polynomial\n  regression of the 3rd order.\n- The initialize_using_file function in the abstract Raster model now transfers\n  information contained in an input GeoTIFF's ModelTiePoint, ModelPixelScale,\n  ModelTransform, GeoKeyDirectory, GeoDoubleParms, and GeoAsciiParams tags to\n  the output raster. This means that if a GeoTIFF file is input to a Whitebox \n  tool, and the output raster is specified to be of GeoTIFF format as well,\n  all of the coordinate information contain in the input raster will now be\n  contained in the output raster.\n- The FeaturePreservingDenoise and DrainagePreservingSmoothing tools, both of\n  which are used for DEM generalization, now represent surface normal vectors \n  using 32-bit floats instead of the original double-precision values. This \n  does not alter the results of these tools significantly, but does reduce the \n  memory requirements and run-times of these tools substantially.\n- The LidarKappa tool now outputs a raster displaying the spatial distribution \n  of the overall accuracy per grid cell (i.e. percent agreement).\n- Fixed a bug with the RasterStreamsToVector tool that resulted in overlapping\n  traced streams.\n- The D8FlowAccumulation tool has been modified to use a fixed flow-width to \n  calculate specific contributing area, equal to the average grid cell resolution. \n  The tool previously used a variable flow-width for SCA calculations, however,\n  1. this differs from the constant value used in Whitebox GAT, and 2. a \n  variable flow-width means that flow accumulation values do not increase \n  continuously in a downstream direction. This last issue was causing problems\n  with applications involving stream network extraction. This change does not\n  affect the 'cells' nor 'catchment area' outputs of the tool.\n- Fixed a bug with the GeoTIFF NoData tag.\n- Fixed a bug with the SetNodataValue tool.\n\n\nVersion 0.12.0 (22-11-2018)\n- The following tools were added to the project:\n    BlockMaximumGridding\n    BlockMinimumGridding\n    Clip\n    Dissolve\n    Erase\n    JoinTables\n    Intersect\n    LasToShapefile\n    LidarClassifySubset\n    LinearityIndex\n    LineIntersections\n    LongestFlowpath\n    MergeTableWithCsv\n    MergeVectors\n    NearestNeighbourGridding\n    PatchOrientation\n    Polygonize\n    RasterToVectorLines\n    SplitWithLines\n    SymmetricalDifference\n    Union\n    VoronoiDiagram\n\n- Modified the algorithm used by the CostDistance tool from an iterative method of\n  finding the minimum cost surface to one that uses a priority-flood approach. This\n  is far more efficient. Also, there was a bug in the original code that was the \n  result of a mismatch between the neighbouring cell distances and the back-link \n  direction. In some cases this resulted in an infinite loop, which is now resolved.\n- Improvements have been made to the WhiteboxTools GeoTIFF reader. A bug has been\n  fixed that prevented tile-oriented (in contrast to the more common strip-oriented)\n  TIFF files from being read properly. Support has been added for reading rasters\n  that have been compressed using the DEFLATE algorithm. Lastly, the WhiteboxTools\n  GeoTIFF reader now supports sparse rasters, as implemented by GDAL's GeoTIFF driver.\n- An issue in the SAGA raster format reader has been fixed.\n\n\nVersion 0.11.0 (01-10-2018)\n- This release is marked by the addition of several vector data processing capabilities. \n  Most notably, this includes support for TINing and TIN based gridding (vector and \n  LiDAR), as well as several vector patch shape indices. The following tools were \n  added to the project:\n    AddPointCoordinatesToTable\n    CentroidVector\n    CompactnessRatio\n    ConstructVectorTIN\n    ElongationRatio\n    ExtendVectorLines\n    HoleProportion\n    LayerFootprint\n    LidarConstructVectorTIN\n    LidarTINGridding\n    LinesToPolygons\n    Medoid\n    MinimumBoundingCircle\n    MinimumBoundingEnvelope\n    MultiPartToSinglePart\n    PerimeterAreaRatio\n    PolygonArea\n    PolygonPerimeter\n    RasterStreamsToVector\n    RasterToVectorPoints\n    RelatedCircumscribingCircle\n    RemovePolygonHoles\n    ShapeComplexityIndex\n    SinglePartToMultiPart\n    SmoothVectors\n    SumOverlay\n    TINGridding\n\n- Added a minimum number of neighbours criteria in the neighbourhood search of the\n  LidarGroundPointFilter tool. In this way, if the fixed-radius search yields fewer\n  neighbours than this minimum neighbours threshold, a second kNN search is carried\n  out to identify the k nearest neighbours. This can be preferable for cases where\n  the point density varies significantly in the data set, e.g. in the case of \n  terrestrial LiDAR point clouds.\n- The MinimumBoundingBox tool has been modified to take an optional minimization \n  criteria, including minimum box area, length, width, or perimeter.\n- Fixed: Bug that resulted in a 0.5 m offset in the positioning of interpolated grids.\n- Fixed: Viewshed tool now emits an intelligible error when the viewing station does \n  not overlap with the DEM.\n\n\nVersion 0.10.0 (16-09-2018)\n- The following tools were added to the project:\n    CreateHexagonalVectorGrid\n    CreateRectangularVectorGrid\n    DrainagePreservingSmoothing\n    EliminateCoincidentPoints\n    ExtractNodes\n    HighPassMedianFilter\n    LasToMultipointShapefile\n    LidarHexBinning and VectorHexBinning\n    LidarTileFootprint\n    MaxDifferenceFromMean\n    MinimumBoundingBox\n    MinimumConvexHull\n    PolygonLongAxis and PolygonShortAxis\n    PolygonsToLines\n    ReinitializeAttributeTable\n\n- Refactoring of some data related to Point2D, and common algorithms (e.g. \n  point-in-poly, convex hull).\n- Added unit tests to BoundingBox, point_in_poly, convex_hull, and elsewhere.\n- Fixed a bug in LiDAR join related to tiles with fewer than two points. LAS files\n  now issue a warning upon saving when they contain less than two points.\n- The default callback can now be modified in whitebox_tools.py, such that\n  a single custom callback can be used without having to specify it for each\n  tool function call.\n- Added initial support for getting projection ESPG and WKT info from LAS files \n  and GeoTiff data. This is the start of a more fullsome approach to handling\n  spatial reference system information in the library.\n- Fixed a bug in saving Shapefile m and z data.\n- Fixed a bug that wouldn't allow the LidarIdwInterpolation and \n  LidarNearestNeighbourGridding tool to interpolate point classification data.\n- LidarGroundPointFilter now has the ability to output a classified LAS file rather \n  than merely filtering non-ground points. Ground points are assigned classification\n  values of 2 while non-ground points are classified as 1.\n- Updated the LidarKappaIndex tool to use a NN-search to find matching points between\n  the compared point clouds.\n- Modified the FixedRadiusSearch structure to use 64-bit floats for storing coordinates.\n  This impacts performance efficiency but is needed for the fine precision of \n  positional information found in terrestrial LiDAR data. FixedRadiusSearch structures\n  have also had approximate kNN search methods added.\n\n\nVersion 0.9.0 (22-08-2018)\n- Added the following tools:\n    ExtractRasterValuesAtPoints\n    FindLowestOrHighestPoints\n    LidarThinHighDensity\n    SelectTilesByPolygon\n    StandardDeviationOfSlope\n    \n- Support has been added for writing Shapefile vector data.\n- The SnapPourPoints and JensonSnapPourPoints tools have been modified to accept\n  vector inputs and to produce vector outputs. This is more consistent with \n  the Watershed tool, which requires vector pour point data inputs.\n\n\nVersion 0.8.0 (30-05-2018)\n- Added the following tools:\n    CornerDetection\n    FastAlmostGaussianFilter\n    GaussianContrastStretch\n    IdwInterpolation\n    ImpoundmentIndex\n    LidarThin\n    StochasticDepressionAnalysis\n    UnsharpMasking\n    WeightedOverlay\n- Modified some filters to take RGB inputs by operating on the intensity value. \n  These include AdaptiveFilter, BilateralFilter, ConservativeSmoothingFilter, \n  DiffOfGaussianFilter, EdgePreservingMeanFilter, EmbossFilter, GaussianFilter, \n  HighPassFilter, KNearestMeanFilter, LaplacianFilter, LaplacianOfGaussianFilter, \n  LeeFilter, MaximumFilter, MeanFilter, MedianFilter, MinimumFilter, OlympicFilter, \n  PrewittFilter, RangeFilter, RobertsCrossFilter, ScharrFilter, SobelFilter, and\n  UserDefinedWeightsFilter.\n- Fixed a bug with reading/writing Whitebox Raster files containing RGB data.\n- Modified the MajorityFilter tool to improve efficiency substantially. Also fixed\n  a bug in it and the DiversityFilter tools.\n\n\nVersion 0.7.0 (01-05-2018)\n- Added the following tools:\n    AttributeCorrelation\n    ChangeVectorAnalysis\n    ClassifyOverlapPoints\n    ClipLidarToPolygon\n    ClipRasterToPolygon\n    CorrectVignetting\n    ErasePolygonFromLidar\n    ExportTableToCsv\n    RaiseWalls\n    TrendSurface\n    TrendSurfaceVectorPoints\n    UnnestBasins\n    UserDefinedWeightsFilter\n- Updated TraceDownslopeFlowpaths to take vector seed point inputs.\n\nVersion 0.6.0 (22-04-2018)\n- Added the ability to read Shapefile attribute data (.dbf files).\n- Added support to read LZW compressed GeoTIFFs, at least for simple\n  single-band files. The decoder can also handle the use of a horizontal\n  predictor (TIFF Tag 317).\n- The following tools have been added in this release:\n    AttributeHistogram\n    AttributeScattergram\n    CountIf\n    ListUniqueValues\n    VectorLinesToRaster\n    VectorPointsToRaster\n    VectorPolygonsToRaster\n\nVersion 0.5.1 (11-04-2018)\n- This minor-point release fixes a far-reaching regression bug caused by a \n  change to the Raster class in the previous release. The change was \n  needed for the in-place operator tools added in the last update. This\n  modification however affected the proper running of several other tools\n  in the library, particularly those in the Math and Stats toolbox. The\n  issue has now been resolved. \n- The VisibilityIndex tool has been added to the library. This is one \n  of the most computationally intensive tools in the library and should\n  really only be used in a high \n- Modified tools with integer parameter inputs to parse strings \n  representations of floating point numbers. Previously, feeding\n  a tool 'filter_size=3.0' would cause a fatal error.\n- Changed Raster so that when a filename with no extension is provided\n  as a parameter input to a tool, it defaults to a GeoTIFF.\n- Added a new section to the User Manual titled, 'An Example WhiteboxTools \n  Python Project'. This addition provides a demonstration of how to\n  set-up a WhiteboxTools Python project, including the file structure\n  needed to import the library.\n\nVersion 0.5.0 (04-04-2018)\n\n- The following tools have been added:\n    EdgePreservingMeanFilter\n    ElevationAboveStreamEuclidean\n    ErasePolygonFromRaster\n    FillBurn\n    FlattenLakes\n    ImageStackProfile\n    InPlaceAdd\n    InPlaceDivide\n    InPlaceMultiply\n    InPlaceSubtract\n    MaxAnisotropyDevSignature\n    PrincipalComponentAnalysis\n    RasterizeStreams\n    \n- Updated tools so that the reporting of elapsed time respects verbose mode.\n- Raster now allows for opening an existing raster in write mode ('w'), needed \n  for the in-place math operators (e.g. InPlaceAdd).\n- Added update_display_min_max function to Raster.\n- Output tables now highlight rows when the mouse hovers.\n\nVersion 0.4.0 (04-03-2018)\n\n- This release has erognomic improvements for Python scripting with Whitebox. Tools can be called \n  in Python like this:\n\n  wt = WhiteboxTools()\n  wt.slope(‘DEM.dep’, ‘slope.dep’)\n  \n- There is a convenience method in whitebox_tools.py for each tool in the WhiteboxTools binary \n  executable. This makes it far easier to call tools from a Python script. See the User Manual\n  for details.\n- Significant improvements and revisions have been made to the User Manual, and in particular \n  the section on Python based scripting with WhiteboxTools.\n- The following tools have been added to the library:\n    LidarColourize\n    LidarPointStats\n    LidarRemoveDuplicates\n    LongProfile\n    LongProfileFromPoints\n    MaxElevDevSignature\n    MultiscaleRoughness\n    MultiscaleRoughnessSignature\n    PrintGeoTiffTags\n    Profile\n- Updated Watershed and Viewshed tools to take vector point inputs.\n- PennockLandformClass tool modified to have int8 output data type. Also fixed a bug in the input\n  parameters.\n\nVersion 0.3.1 (15-02-2018)\n\n- No new tools have been added to this release. Instead the focus was on improving and enhancing\n  LAS file support and fixing a numbe of bugs. These include the following:\n- Support has been added in the LAS file reader for handling Point Record Formats 4-11 in the \n  LAS 1.4 specifications. This includes enhanced support for 64-bit LAS files. This change \n  resulted in cascading changes throughout the LiDAR infrastructure and LiDAR tools. Future \n  work will focus on writing LAS files in 1.4 format, instead of the current 1.3 format that is\n  saved.\n- The LidarIdwInterpolation, LidarNearestNeighbourGridding, and LidarPointDensity tools have each\n  been modified to enhance the granularity of parallelism when operating in multi-file mode. This \n  has resulted in large improvements in performance when interpolating entire directories of \n  LAS files.\n- The LasHeader object now has the ability to read a LAS header directly. This allows \n  interrogation of a LAS file without the need to create a full LAS object. This was useful \n  for identifying neighbouring tiles during interpolation, such that a buffer of points \n  from adjacent tiles can be used, thereby minimizing interpolation edge effects.\n- There was a bug with the WhiteboxTools Runner that had issue with the use of a forward-slash (/) \n  in file paths on Windows. These have been fixed now. I also fixed every tool such that the use\n  of a forward slash for file paths on Windows won't result in an additional working directory \n  being appended to file names. This one resulted in many files being slightly modified.\n- Added the ability to select the working directory in WhiteboxTools Runner. This is a useful\n  feature because some of the LiDAR tools now allow for no specified input/output files, in \n  which case they operate on all of the LAS files contained within the working directory.\n\nVersion 0.3 (07-02-2018)\n\n- Added the following tools:\n    MaxAnisotropyDev\n    HysometricAnalysis\n    SlopeVsElevationPlot\n    LidarRemoveOutliers\n\n- Added initial support for reading Shapefile geometries. This is still a proof-of-concept\n  and no tools as of yet use Shapefile inputs. \n- Added functionality to create beautiful and interactive line graph and scattergram \n  outputs for tools.\n- LiDAR interpolation tools now have the option to interpolate all LAS files within the \n  working directory when an input file name is not specified.\n- Added first draft of a pdf user manual for WhiteboxTools.\n\nVersion 0.2 (12-01-2018)\n\n- Added the following tools:\n    KSTestForNormality\n    RadomSample\n    Mosaic\n    Resample\n    RadiusOfGyration\n    KMeansClustering\n    ModifiedKMeansClustering\n    D8MassFlux\n    DInfMassFlux\n    RasterHistogram\n    LidarHistogram\n    CrossTabulation\n    ImageAutocorrelation\n    ExtractRasterStatistics\n    AggregateRaster\n    Viewshed\n\n- Fixed several bugs including one affecting the reading of LAS files.\n\n- Numerous enhancements"
  },
  {
    "path": "WBT/wb_runner.py",
    "content": "#!/usr/bin/env python3\n\n# This script is part of the WhiteboxTools geospatial analysis library.\n# Authors: Dr. John Lindsay, Rachel Broders\n# Created: 28/11/2017\n# Last Modified: 05/11/2019\n# License: MIT\n\nimport __future__\nimport sys\n# if sys.version_info[0] < 3:\n#     raise Exception(\"Must be using Python 3\")\nimport json\nimport os\nfrom os import path\n# from __future__ import print_function\n# from enum import Enum\nimport platform\nimport re    #Added by Rachel for snake_to_camel function\nfrom pathlib import Path\nimport glob\nfrom sys import platform as _platform\nimport shlex\nimport tkinter as tk\nfrom tkinter import ttk\nfrom tkinter.scrolledtext import ScrolledText\nfrom tkinter import filedialog\nfrom tkinter.simpledialog import askinteger\nfrom tkinter import messagebox\nfrom tkinter import PhotoImage\nimport webbrowser\nfrom whitebox_tools import WhiteboxTools, to_camelcase\n\nwbt = WhiteboxTools()\n\n\nclass FileSelector(tk.Frame):\n    def __init__(self, json_str, runner, master=None):\n        # first make sure that the json data has the correct fields\n        j = json.loads(json_str)\n        self.name = j['name']\n        self.description = j['description']\n        self.flag = j['flags'][len(j['flags']) - 1]\n        self.parameter_type = j['parameter_type']\n        self.file_type = \"\"\n        if \"ExistingFile\" in self.parameter_type:\n            self.file_type = j['parameter_type']['ExistingFile']\n        elif \"NewFile\" in self.parameter_type:\n            self.file_type = j['parameter_type']['NewFile']\n        self.optional = j['optional']\n        default_value = j['default_value']\n\n        self.runner = runner\n\n        ttk.Frame.__init__(self, master, padding='0.02i')\n        self.grid()\n\n        self.label = ttk.Label(self, text=self.name, justify=tk.LEFT)\n        self.label.grid(row=0, column=0, sticky=tk.W)\n        self.label.columnconfigure(0, weight=1)\n\n        if not self.optional:\n            self.label['text'] = self.label['text'] + \"*\"\n\n        fs_frame = ttk.Frame(self, padding='0.0i')\n        self.value = tk.StringVar()\n        self.entry = ttk.Entry(\n            fs_frame, width=45, justify=tk.LEFT, textvariable=self.value)\n        self.entry.grid(row=0, column=0, sticky=tk.NSEW)\n        self.entry.columnconfigure(0, weight=1)\n        if default_value:\n            self.value.set(default_value)\n\n        # dir_path = os.path.dirname(os.path.realpath(__file__))\n        # print(dir_path)\n        # self.open_file_icon = tk.PhotoImage(file =  dir_path + '//img//open.png')     #Added by Rachel to replace file selector \"...\" button with open file icon\n        \n        # self.open_button = ttk.Button(fs_frame, width=4, image = self.open_file_icon, command=self.select_file, padding = '0.02i')\n        self.open_button = ttk.Button(fs_frame, width=4, text=\"...\", command=self.select_file, padding = '0.02i')\n        self.open_button.grid(row=0, column=1, sticky=tk.E)\n        self.open_button.columnconfigure(0, weight=1)\n        fs_frame.grid(row=1, column=0, sticky=tk.NSEW)\n        fs_frame.columnconfigure(0, weight=10)\n        fs_frame.columnconfigure(1, weight=1)\n        # self.pack(fill=tk.BOTH, expand=1)\n        self.columnconfigure(0, weight=1)\n        self.rowconfigure(0, weight=1)\n        self.rowconfigure(1, weight=1)\n\n        # Add the bindings\n        if _platform == \"darwin\":\n            self.entry.bind(\"<Command-Key-a>\", self.select_all)\n        else:\n            self.entry.bind(\"<Control-Key-a>\", self.select_all)\n\n    def select_file(self):\n        try:\n            result = self.value.get()\n            if self.parameter_type == \"Directory\":\n                result = filedialog.askdirectory(initialdir=self.runner.working_dir, title=\"Select directory\")\n            elif \"ExistingFile\" in self.parameter_type:\n                ftypes = [('All files', '*.*')]\n                if 'RasterAndVector' in self.file_type:\n                    ftypes = [(\"Shapefiles\", \"*.shp\"), ('Raster files', ('*.dep', '*.tif',\n                                                '*.tiff', '*.bil', '*.flt',\n                                                '*.sdat', '*.rdc',\n                                                '*.asc', '*grd'))]\n                elif 'Raster' in self.file_type:\n                    ftypes = [('Raster files', ('*.dep', '*.tif',\n                                                '*.tiff', '*.bil', '*.flt',\n                                                '*.sdat', '*.rdc',\n                                                '*.asc', '*.grd'))]\n                elif 'Lidar' in self.file_type:\n                    ftypes = [(\"LiDAR files\", ('*.las', '*.zlidar', '*.laz', '*.zip'))]\n                elif 'Vector' in self.file_type:\n                    ftypes = [(\"Shapefiles\", \"*.shp\")]\n                elif 'Text' in self.file_type:\n                    ftypes = [(\"Text files\", \"*.txt\"), (\"all files\", \"*.*\")]\n                elif 'Csv' in self.file_type:\n                    ftypes = [(\"CSC files\", \"*.csv\"), (\"all files\", \"*.*\")]\n                elif 'Dat' in self.file_type:\n                    ftypes = [(\"Binary data files\", \"*.dat\"), (\"all files\", \"*.*\")]\n                elif 'Html' in self.file_type:\n                    ftypes = [(\"HTML files\", \"*.html\")]\n\n                result = filedialog.askopenfilename(\n                    initialdir=self.runner.working_dir, title=\"Select file\", filetypes=ftypes)\n\n            elif \"NewFile\" in self.parameter_type:\n                result = filedialog.asksaveasfilename()\n\n            self.value.set(result)\n            # update the working directory\n            self.runner.working_dir = os.path.dirname(result)\n\n        except:\n            t = \"file\"\n            if self.parameter_type == \"Directory\":\n                t = \"directory\"\n            messagebox.showinfo(\"Warning\", \"Could not find {}\".format(t))\n\n    def get_value(self):\n        if self.value.get():\n            v = self.value.get()\n            # Do some quality assurance here.\n            # Is there a directory included?\n            if not path.dirname(v):\n                v = path.join(self.runner.working_dir, v)\n\n            # What about a file extension?\n            ext = os.path.splitext(v)[-1].lower().strip()\n            if not ext:\n                ext = \"\"\n                if 'RasterAndVector' in self.file_type:\n                    ext = '.tif'\n                elif 'Raster' in self.file_type:\n                    ext = '.tif'\n                elif 'Lidar' in self.file_type:\n                    ext = '.las'\n                elif 'Vector' in self.file_type:\n                    ext = '.shp'\n                elif 'Text' in self.file_type:\n                    ext = '.txt'\n                elif 'Csv' in self.file_type:\n                    ext = '.csv'\n                elif 'Html' in self.file_type:\n                    ext = '.html'\n\n                v += ext\n\n            v = path.normpath(v)\n\n            return \"{}='{}'\".format(self.flag, v)\n        else:\n            t = \"file\"\n            if self.parameter_type == \"Directory\":\n                t = \"directory\"\n            if not self.optional:\n                messagebox.showinfo(\n                    \"Error\", \"Unspecified {} parameter {}.\".format(t, self.flag))\n\n        return None\n\n    def select_all(self, event):\n        self.entry.select_range(0, tk.END)\n        return 'break'\n\n\nclass FileOrFloat(tk.Frame):\n    def __init__(self, json_str, runner, master=None):\n        # first make sure that the json data has the correct fields\n        j = json.loads(json_str)\n        self.name = j['name']\n        self.description = j['description']\n        self.flag = j['flags'][len(j['flags']) - 1]\n        self.parameter_type = j['parameter_type']\n        self.file_type = j['parameter_type']['ExistingFileOrFloat']\n        self.optional = j['optional']\n        default_value = j['default_value']\n\n        self.runner = runner\n\n        ttk.Frame.__init__(self, master)\n        self.grid()\n        self['padding'] = '0.02i'\n\n        self.label = ttk.Label(self, text=self.name, justify=tk.LEFT)\n        self.label.grid(row=0, column=0, sticky=tk.W)\n        self.label.columnconfigure(0, weight=1)\n\n        if not self.optional:\n            self.label['text'] = self.label['text'] + \"*\"\n\n        fs_frame = ttk.Frame(self, padding='0.0i')\n        self.value = tk.StringVar()\n        self.entry = ttk.Entry(\n            fs_frame, width=35, justify=tk.LEFT, textvariable=self.value)\n        self.entry.grid(row=0, column=0, sticky=tk.NSEW)\n        self.entry.columnconfigure(0, weight=1)\n        if default_value:\n            self.value.set(default_value)\n\n        # self.img = tk.PhotoImage(file=script_dir + \"/img/open.gif\")\n        # self.open_button = ttk.Button(fs_frame, width=55, image=self.img, command=self.select_dir)\n        self.open_button = ttk.Button(\n            fs_frame, width=4, text=\"...\", command=self.select_file)\n        self.open_button.grid(row=0, column=1, sticky=tk.E)\n        # self.open_button.columnconfigure(0, weight=1)\n\n        self.label = ttk.Label(fs_frame, text='OR', justify=tk.LEFT)\n        self.label.grid(row=0, column=2, sticky=tk.W)\n        # self.label.columnconfigure(0, weight=1)\n\n        self.value2 = tk.StringVar()\n        self.entry2 = ttk.Entry(\n            fs_frame, width=10, justify=tk.LEFT, textvariable=self.value2)\n        self.entry2.grid(row=0, column=3, sticky=tk.NSEW)\n        self.entry2.columnconfigure(0, weight=1)\n        self.entry2['justify'] = 'right'\n\n        fs_frame.grid(row=1, column=0, sticky=tk.NSEW)\n        fs_frame.columnconfigure(0, weight=10)\n        fs_frame.columnconfigure(1, weight=1)\n        # self.pack(fill=tk.BOTH, expand=1)\n        self.columnconfigure(0, weight=1)\n        self.rowconfigure(0, weight=1)\n        self.rowconfigure(1, weight=1)\n\n        # Add the bindings\n        if _platform == \"darwin\":\n            self.entry.bind(\"<Command-Key-a>\", self.select_all)\n        else:\n            self.entry.bind(\"<Control-Key-a>\", self.select_all)\n\n    def select_file(self):\n        try:\n            result = self.value.get()\n            ftypes = [('All files', '*.*')]\n            if 'RasterAndVector' in self.file_type:\n                    ftypes = [(\"Shapefiles\", \"*.shp\"), ('Raster files', ('*.dep', '*.tif',\n                                                '*.tiff', '*.bil', '*.flt',\n                                                '*.sdat', '*.rdc',\n                                                '*.asc'))]\n            elif 'Raster' in self.file_type:\n                ftypes = [('Raster files', ('*.dep', '*.tif',\n                                            '*.tiff', '*.bil', '*.flt',\n                                            '*.sdat', '*.rdc',\n                                            '*.asc'))]\n            elif 'Lidar' in self.file_type:\n                ftypes = [(\"LiDAR files\", ('*.las', '*.zlidar', '*.laz', '*.zip'))]\n            elif 'Vector' in self.file_type:\n                ftypes = [(\"Shapefiles\", \"*.shp\")]\n            elif 'Text' in self.file_type:\n                ftypes = [(\"Text files\", \"*.txt\"), (\"all files\", \"*.*\")]\n            elif 'Csv' in self.file_type:\n                ftypes = [(\"CSC files\", \"*.csv\"), (\"all files\", \"*.*\")]\n            elif 'Html' in self.file_type:\n                ftypes = [(\"HTML files\", \"*.html\")]\n\n            result = filedialog.askopenfilename(\n                initialdir=self.runner.working_dir, title=\"Select file\", filetypes=ftypes)\n\n            self.value.set(result)\n            # update the working directory\n            self.runner.working_dir = os.path.dirname(result)\n\n        except:\n            t = \"file\"\n            if self.parameter_type == \"Directory\":\n                t = \"directory\"\n            messagebox.showinfo(\"Warning\", \"Could not find {}\".format(t))\n\n    def RepresentsFloat(self, s):\n        try:\n            float(s)\n            return True\n        except ValueError:\n            return False\n\n    def get_value(self):\n        if self.value.get():\n            v = self.value.get()\n            # Do some quality assurance here.\n            # Is there a directory included?\n            if not path.dirname(v):\n                v = path.join(self.runner.working_dir, v)\n\n            # What about a file extension?\n            ext = os.path.splitext(v)[-1].lower()\n            if not ext:\n                ext = \"\"\n                if 'RasterAndVector' in self.file_type:\n                    ext = '.tif'\n                elif 'Raster' in self.file_type:\n                    ext = '.tif'\n                elif 'Lidar' in self.file_type:\n                    ext = '.las'\n                elif 'Vector' in self.file_type:\n                    ext = '.shp'\n                elif 'Text' in self.file_type:\n                    ext = '.txt'\n                elif 'Csv' in self.file_type:\n                    ext = '.csv'\n                elif 'Html' in self.file_type:\n                    ext = '.html'\n\n                v = v + ext\n\n            v = path.normpath(v)\n\n            return \"{}='{}'\".format(self.flag, v)\n        elif self.value2.get():\n            v = self.value2.get()\n            if self.RepresentsFloat(v):\n                return \"{}={}\".format(self.flag, v)\n            else:\n                messagebox.showinfo(\n                    \"Error\", \"Error converting parameter {} to type Float.\".format(self.flag))\n        else:\n            if not self.optional:\n                messagebox.showinfo(\n                    \"Error\", \"Unspecified file/numeric parameter {}.\".format(self.flag))\n\n        return None\n\n    def select_all(self, event):\n        self.entry.select_range(0, tk.END)\n        return 'break'\n\n\nclass MultifileSelector(tk.Frame):\n    def __init__(self, json_str, runner, master=None):\n        # first make sure that the json data has the correct fields\n        j = json.loads(json_str)\n        self.name = j['name']\n        self.description = j['description']\n        self.flag = j['flags'][len(j['flags']) - 1]\n        self.parameter_type = j['parameter_type']\n        self.file_type = \"\"\n        self.file_type = j['parameter_type']['FileList']\n        self.optional = j['optional']\n        default_value = j['default_value']\n\n        self.runner = runner\n\n        ttk.Frame.__init__(self, master)\n        self.grid()\n        self['padding'] = '0.05i'\n\n        self.label = ttk.Label(self, text=self.name, justify=tk.LEFT)\n        self.label.grid(row=0, column=0, sticky=tk.W)\n        self.label.columnconfigure(0, weight=1)\n\n        if not self.optional:\n            self.label['text'] = self.label['text'] + \"*\"\n\n        fs_frame = ttk.Frame(self, padding='0.0i')\n        # , variable=self.value)\n        self.opt = tk.Listbox(fs_frame, width=44, height=4)\n        self.opt.grid(row=0, column=0, sticky=tk.NSEW)\n        s = ttk.Scrollbar(fs_frame, orient=tk.VERTICAL, command=self.opt.yview)\n        s.grid(row=0, column=1, sticky=(tk.N, tk.S))\n        self.opt['yscrollcommand'] = s.set\n\n        btn_frame = ttk.Frame(fs_frame, padding='0.0i')\n        self.open_button = ttk.Button(\n            btn_frame, width=4, text=\"...\", command=self.select_file)\n        self.open_button.grid(row=0, column=0, sticky=tk.NE)\n        self.open_button.columnconfigure(0, weight=1)\n        self.open_button.rowconfigure(0, weight=1)\n\n        self.delete_button = ttk.Button(\n            btn_frame, width=4, text=\"del\", command=self.delete_entry)\n        self.delete_button.grid(row=1, column=0, sticky=tk.NE)\n        self.delete_button.columnconfigure(0, weight=1)\n        self.delete_button.rowconfigure(1, weight=1)\n\n        btn_frame.grid(row=0, column=2, sticky=tk.NE)\n\n        fs_frame.grid(row=1, column=0, sticky=tk.NSEW)\n        fs_frame.columnconfigure(0, weight=10)\n        fs_frame.columnconfigure(1, weight=1)\n        fs_frame.columnconfigure(2, weight=1)\n        # self.pack(fill=tk.BOTH, expand=1)\n        self.columnconfigure(0, weight=1)\n        self.rowconfigure(0, weight=1)\n        self.rowconfigure(1, weight=1)\n\n    def select_file(self):\n        try:\n            #result = self.value.get()\n            init_dir = self.runner.working_dir\n            ftypes = [('All files', '*.*')]\n            if 'RasterAndVector' in self.file_type:\n                    ftypes = [(\"Shapefiles\", \"*.shp\"), ('Raster files', ('*.dep', '*.tif',\n                                                '*.tiff', '*.bil', '*.flt',\n                                                '*.sdat', '*.rdc',\n                                                '*.asc'))]\n            elif 'Raster' in self.file_type:\n                ftypes = [('Raster files', ('*.dep', '*.tif',\n                                            '*.tiff', '*.bil', '*.flt',\n                                            '*.sdat', '*.rdc',\n                                            '*.asc'))]\n            elif 'Lidar' in self.file_type:\n                ftypes = [(\"LiDAR files\", ('*.las', '*.zlidar', '*.laz', '*.zip'))]\n            elif 'Vector' in self.file_type:\n                ftypes = [(\"Shapefiles\", \"*.shp\")]\n            elif 'Text' in self.file_type:\n                ftypes = [(\"Text files\", \"*.txt\"), (\"all files\", \"*.*\")]\n            elif 'Csv' in self.file_type:\n                ftypes = [(\"CSC files\", \"*.csv\"), (\"all files\", \"*.*\")]\n            elif 'Html' in self.file_type:\n                ftypes = [(\"HTML files\", \"*.html\")]\n\n            result = filedialog.askopenfilenames(\n                initialdir=init_dir, title=\"Select files\", filetypes=ftypes)\n            if result:\n                for v in result:\n                    self.opt.insert(tk.END, v)\n\n                # update the working directory\n                self.runner.working_dir = os.path.dirname(result[0])\n\n        except:\n            messagebox.showinfo(\"Warning\", \"Could not find file\")\n\n    def delete_entry(self):\n        self.opt.delete(tk.ANCHOR)\n\n    def get_value(self):\n        try:\n            l = self.opt.get(0, tk.END)\n            if l:\n                s = \"\"\n                for i in range(0, len(l)):\n                    v = l[i]\n                    if not path.dirname(v):\n                        v = path.join(self.runner.working_dir, v)\n                    v = path.normpath(v)\n                    if i < len(l) - 1:\n                        s += \"{};\".format(v)\n                    else:\n                        s += \"{}\".format(v)\n\n                return \"{}='{}'\".format(self.flag, s)\n            else:\n                if not self.optional:\n                    messagebox.showinfo(\n                        \"Error\", \"Unspecified non-optional parameter {}.\".format(self.flag))\n\n        except:\n            messagebox.showinfo(\n                \"Error\", \"Error formatting files for parameter {}\".format(self.flag))\n\n        return None\n\n\nclass BooleanInput(tk.Frame):\n    def __init__(self, json_str, master=None):\n        # first make sure that the json data has the correct fields\n        j = json.loads(json_str)\n        self.name = j['name']\n        self.description = j['description']\n        self.flag = j['flags'][len(j['flags']) - 1]\n        self.parameter_type = j['parameter_type']\n        # just for quality control. BooleanInputs are always optional.\n        self.optional = True\n        default_value = j['default_value']\n\n        ttk.Frame.__init__(self, master)\n        self.grid()\n        self['padding'] = '0.05i'\n\n        frame = ttk.Frame(self, padding='0.0i')\n\n        self.value = tk.IntVar()\n        c = ttk.Checkbutton(frame, text=self.name,\n                            width=55, variable=self.value)\n        c.grid(row=0, column=0, sticky=tk.W)\n\n        # set the default value\n        if j['default_value'] != None and j['default_value'] != 'false':\n            self.value.set(1)\n        else:\n            self.value.set(0)\n\n        frame.grid(row=1, column=0, sticky=tk.W)\n        frame.columnconfigure(0, weight=1)\n\n        # self.pack(fill=tk.BOTH, expand=1)\n        self.columnconfigure(0, weight=1)\n        self.rowconfigure(0, weight=1)\n\n    def get_value(self):\n        if self.value.get() == 1:\n            return self.flag\n        else:\n            return None\n\n\nclass OptionsInput(tk.Frame):\n    def __init__(self, json_str, master=None):\n        # first make sure that the json data has the correct fields\n        j = json.loads(json_str)\n        self.name = j['name']\n        self.description = j['description']\n        self.flag = j['flags'][len(j['flags']) - 1]\n        self.parameter_type = j['parameter_type']\n        self.optional = j['optional']\n        default_value = j['default_value']\n\n        ttk.Frame.__init__(self, master)\n        self.grid()\n        self['padding'] = '0.02i'\n\n        frame = ttk.Frame(self, padding='0.0i')\n\n        self.label = ttk.Label(self, text=self.name, justify=tk.LEFT)\n        self.label.grid(row=0, column=0, sticky=tk.W)\n        self.label.columnconfigure(0, weight=1)\n\n        frame2 = ttk.Frame(frame, padding='0.0i')\n        opt = ttk.Combobox(frame2, width=40)\n        opt.grid(row=0, column=0, sticky=tk.NSEW)\n\n        self.value = None  # initialize in event of no default and no selection\n        i = 1\n        default_index = -1\n        list = j['parameter_type']['OptionList']\n        values = ()\n        for v in list:\n            values += (v,)\n            # opt.insert(tk.END, v)\n            if v == default_value:\n                default_index = i - 1\n            i = i + 1\n\n        opt['values'] = values\n\n        # opt.bind(\"<<ComboboxSelect>>\", self.select)\n        opt.bind(\"<<ComboboxSelected>>\", self.select)\n        if default_index >= 0:\n            opt.current(default_index)\n            opt.event_generate(\"<<ComboboxSelected>>\")\n            # opt.see(default_index)\n\n        frame2.grid(row=0, column=0, sticky=tk.W)\n        frame.grid(row=1, column=0, sticky=tk.W)\n        frame.columnconfigure(0, weight=1)\n\n        # self.pack(fill=tk.BOTH, expand=1)\n        self.columnconfigure(0, weight=1)\n        self.rowconfigure(0, weight=1)\n\n        # # first make sure that the json data has the correct fields\n        # j = json.loads(json_str)\n        # self.name = j['name']\n        # self.description = j['description']\n        # self.flag = j['flags'][len(j['flags']) - 1]\n        # self.parameter_type = j['parameter_type']\n        # self.optional = j['optional']\n        # default_value = j['default_value']\n\n        # ttk.Frame.__init__(self, master)\n        # self.grid()\n        # self['padding'] = '0.1i'\n\n        # frame = ttk.Frame(self, padding='0.0i')\n\n        # self.label = ttk.Label(self, text=self.name, justify=tk.LEFT)\n        # self.label.grid(row=0, column=0, sticky=tk.W)\n        # self.label.columnconfigure(0, weight=1)\n\n        # frame2 = ttk.Frame(frame, padding='0.0i')\n        # opt = tk.Listbox(frame2, width=40)  # , variable=self.value)\n        # opt.grid(row=0, column=0, sticky=tk.NSEW)\n        # s = ttk.Scrollbar(frame2, orient=tk.VERTICAL, command=opt.yview)\n        # s.grid(row=0, column=1, sticky=(tk.N, tk.S))\n        # opt['yscrollcommand'] = s.set\n\n        # self.value = None  # initialize in event of no default and no selection\n        # i = 1\n        # default_index = -1\n        # list = j['parameter_type']['OptionList']\n        # for v in list:\n        #     #opt.insert(i, v)\n        #     opt.insert(tk.END, v)\n        #     if v == default_value:\n        #         default_index = i - 1\n        #     i = i + 1\n\n        # if i - 1 < 4:\n        #     opt['height'] = i - 1\n        # else:\n        #     opt['height'] = 3\n\n        # opt.bind(\"<<ListboxSelect>>\", self.select)\n        # if default_index >= 0:\n        #     opt.select_set(default_index)\n        #     opt.event_generate(\"<<ListboxSelect>>\")\n        #     opt.see(default_index)\n\n        # frame2.grid(row=0, column=0, sticky=tk.W)\n        # frame.grid(row=1, column=0, sticky=tk.W)\n        # frame.columnconfigure(0, weight=1)\n\n        # # self.pack(fill=tk.BOTH, expand=1)\n        # self.columnconfigure(0, weight=1)\n        # self.rowconfigure(0, weight=1)\n\n    def get_value(self):\n        if self.value:\n            return \"{}='{}'\".format(self.flag, self.value)\n        else:\n            if not self.optional:\n                messagebox.showinfo(\n                    \"Error\", \"Unspecified non-optional parameter {}.\".format(self.flag))\n\n        return None\n\n    def select(self, event):\n        widget = event.widget\n        # selection = widget.curselection()\n        self.value = widget.get()  # selection[0])\n\n\nclass DataInput(tk.Frame):\n    def __init__(self, json_str, master=None):\n        # first make sure that the json data has the correct fields\n        j = json.loads(json_str)\n        self.name = j['name']\n        self.description = j['description']\n        self.flag = j['flags'][len(j['flags']) - 1]\n        self.parameter_type = j['parameter_type']\n        self.optional = j['optional']\n        default_value = j['default_value']\n\n        ttk.Frame.__init__(self, master)\n        self.grid()\n        self['padding'] = '0.1i'\n\n        self.label = ttk.Label(self, text=self.name, justify=tk.LEFT)\n        self.label.grid(row=0, column=0, sticky=tk.W)\n        self.label.columnconfigure(0, weight=1)\n\n        self.value = tk.StringVar()\n        if default_value:\n            self.value.set(default_value)\n        else:\n            self.value.set(\"\")\n\n        self.entry = ttk.Entry(self, justify=tk.LEFT, textvariable=self.value)\n        self.entry.grid(row=0, column=1, sticky=tk.NSEW)\n        self.entry.columnconfigure(1, weight=10)\n\n        if not self.optional:\n            self.label['text'] = self.label['text'] + \"*\"\n\n        if (\"Integer\" in self.parameter_type or\n            \"Float\" in self.parameter_type or\n                \"Double\" in self.parameter_type):\n            self.entry['justify'] = 'right'\n\n        # Add the bindings\n        if _platform == \"darwin\":\n            self.entry.bind(\"<Command-Key-a>\", self.select_all)\n        else:\n            self.entry.bind(\"<Control-Key-a>\", self.select_all)\n\n        # self.pack(fill=tk.BOTH, expand=1)\n        self.columnconfigure(0, weight=1)\n        self.columnconfigure(1, weight=10)\n        self.rowconfigure(0, weight=1)\n\n    def RepresentsInt(self, s):\n        try:\n            int(s)\n            return True\n        except ValueError:\n            return False\n\n    def RepresentsFloat(self, s):\n        try:\n            float(s)\n            return True\n        except ValueError:\n            return False\n\n    def get_value(self):\n        v = self.value.get()\n        if v:\n            if \"Integer\" in self.parameter_type:\n                if self.RepresentsInt(self.value.get()):\n                    return \"{}={}\".format(self.flag, self.value.get())\n                else:\n                    messagebox.showinfo(\n                        \"Error\", \"Error converting parameter {} to type Integer.\".format(self.flag))\n            elif \"Float\" in self.parameter_type:\n                if self.RepresentsFloat(self.value.get()):\n                    return \"{}={}\".format(self.flag, self.value.get())\n                else:\n                    messagebox.showinfo(\n                        \"Error\", \"Error converting parameter {} to type Float.\".format(self.flag))\n            elif \"Double\" in self.parameter_type:\n                if self.RepresentsFloat(self.value.get()):\n                    return \"{}={}\".format(self.flag, self.value.get())\n                else:\n                    messagebox.showinfo(\n                        \"Error\", \"Error converting parameter {} to type Double.\".format(self.flag))\n            else:  # String or StringOrNumber types\n                return \"{}='{}'\".format(self.flag, self.value.get())\n        else:\n            if not self.optional:\n                messagebox.showinfo(\n                    \"Error\", \"Unspecified non-optional parameter {}.\".format(self.flag))\n\n        return None\n\n    def select_all(self, event):\n        self.entry.select_range(0, tk.END)\n        return 'break'\n\n\nclass WbRunner(tk.Frame):\n    def __init__(self, tool_name=None, master=None):\n        if platform.system() == 'Windows':\n            self.ext = '.exe'\n        else:\n            self.ext = ''\n\n        exe_name = \"whitebox_tools{}\".format(self.ext)\n\n        self.exe_path = path.dirname(path.abspath(__file__))\n        os.chdir(self.exe_path)\n        for filename in glob.iglob('**/*', recursive=True):\n            if filename.endswith(exe_name):\n                self.exe_path = path.dirname(path.abspath(filename))\n                break\n\n        wbt.set_whitebox_dir(self.exe_path)\n\n        ttk.Frame.__init__(self, master)\n        self.script_dir = os.path.dirname(os.path.realpath(__file__))\n        self.grid()\n        self.tool_name = tool_name\n        self.master.title(\"WhiteboxTools Runner\")\n        if _platform == \"darwin\":\n            os.system(\n                '''/usr/bin/osascript -e 'tell app \"Finder\" to set frontmost of process \"Python\" to true' ''')\n        self.create_widgets()\n        self.working_dir = wbt.get_working_dir() # str(Path.home())\n\n    def create_widgets(self):\n\n        #########################################################\n        #              Overall/Top level Frame                  #\n        #########################################################     \n        #define left-side frame (toplevel_frame) and right-side frame (overall_frame)\n        toplevel_frame = ttk.Frame(self, padding='0.1i')\n        overall_frame = ttk.Frame(self, padding='0.1i')\n        #set-up layout\n        overall_frame.grid(row=0, column=1, sticky=tk.NSEW)\n        toplevel_frame.grid(row=0, column=0, sticky=tk.NSEW)   \n        #########################################################\n        #                  Calling basics                       #\n        #########################################################\n        #Create all needed lists of tools and toolboxes\n        self.toolbox_list = self.get_toolboxes()\n        self.sort_toolboxes()\n        self.tools_and_toolboxes = wbt.toolbox('')\n        self.sort_tools_by_toolbox()        \n        self.get_tools_list()  \n        #Icons to be used in tool treeview\n        self.tool_icon = tk.PhotoImage(file = self.script_dir + '//img//tool.gif')  \n        self.open_toolbox_icon = tk.PhotoImage(file =  self.script_dir + '//img//open.gif')\n        self.closed_toolbox_icon = tk.PhotoImage(file =  self.script_dir + '//img//closed.gif')\n        #########################################################\n        #                  Toolboxes Frame                      # FIXME: change width or make horizontally scrollable\n        #########################################################\n        #define tools_frame and tool_tree\n        self.tools_frame = ttk.LabelFrame(toplevel_frame, text=\"{} Available Tools\".format(len(self.tools_list)), padding='0.1i')   \n        self.tool_tree = ttk.Treeview(self.tools_frame, height = 21)    \n        #Set up layout\n        self.tool_tree.grid(row=0, column=0, sticky=tk.NSEW)\n        self.tool_tree.column(\"#0\", width = 280)    #Set width so all tools are readable within the frame\n        self.tools_frame.grid(row=0, column=0, sticky=tk.NSEW)\n        self.tools_frame.columnconfigure(0, weight=10)\n        self.tools_frame.columnconfigure(1, weight=1)\n        self.tools_frame.rowconfigure(0, weight=10)\n        self.tools_frame.rowconfigure(1, weight=1)\n        #Add toolboxes and tools to treeview\n        index = 0\n        for toolbox in self.lower_toolboxes:\n            if toolbox.find('/') != (-1):    #toolboxes \n                self.tool_tree.insert(toolbox[:toolbox.find('/')], 0, text = \"  \" + toolbox[toolbox.find('/') + 1:], iid = toolbox[toolbox.find('/') + 1:], tags = 'toolbox', image = self.closed_toolbox_icon)\n                for tool in self.sorted_tools[index]:    #add tools within toolbox\n                    self.tool_tree.insert(toolbox[toolbox.find('/') + 1:], 'end', text = \"  \" + tool, tags = 'tool', iid = tool, image = self.tool_icon)       \n            else:    #subtoolboxes\n                self.tool_tree.insert('', 'end', text = \"  \" + toolbox, iid = toolbox, tags = 'toolbox', image = self.closed_toolbox_icon)                         \n                for tool in self.sorted_tools[index]:  #add tools within subtoolbox\n                    self.tool_tree.insert(toolbox, 'end', text = \"  \" + tool, iid = tool, tags = 'tool', image = self.tool_icon) \n            index = index + 1 \n        #bind tools in treeview to self.tree_update_tool_help function and toolboxes to self.update_toolbox_icon function\n        self.tool_tree.tag_bind('tool', \"<<TreeviewSelect>>\", self.tree_update_tool_help)   \n        self.tool_tree.tag_bind('toolbox', \"<<TreeviewSelect>>\", self.update_toolbox_icon)  \n        #Add vertical scrollbar to treeview frame\n        s = ttk.Scrollbar(self.tools_frame, orient=tk.VERTICAL,command=self.tool_tree.yview)    \n        s.grid(row=0, column=1, sticky=(tk.N, tk.S))\n        self.tool_tree['yscrollcommand'] = s.set\n        #########################################################\n        #                     Search Bar                        #\n        #########################################################\n        #create variables for search results and search input\n        self.search_list = []    \n        self.search_text = tk.StringVar()\n        #Create the elements of the search frame\n        self.search_frame = ttk.LabelFrame(toplevel_frame, padding='0.1i', text=\"{} Tools Found\".format(len(self.search_list)))         \n        self.search_label = ttk.Label(self.search_frame, text = \"Search: \") \n        self.search_bar = ttk.Entry(self.search_frame, width = 30, textvariable = self.search_text)\n        self.search_results_listbox = tk.Listbox(self.search_frame, height=11) \n        self.search_scroll = ttk.Scrollbar(self.search_frame, orient=tk.VERTICAL, command=self.search_results_listbox.yview)\n        self.search_results_listbox['yscrollcommand'] = self.search_scroll.set\n        #Add bindings\n        self.search_results_listbox.bind(\"<<ListboxSelect>>\", self.search_update_tool_help)\n        self.search_bar.bind('<Return>', self.update_search)\n        #Define layout of the frame\n        self.search_frame.grid(row = 1, column = 0, sticky=tk.NSEW)\n        self.search_label.grid(row = 0, column = 0, sticky=tk.NW)\n        self.search_bar.grid(row = 0, column = 1, sticky=tk.NE) \n        self.search_results_listbox.grid(row = 1, column = 0, columnspan = 2, sticky=tk.NSEW, pady = 5)\n        self.search_scroll.grid(row=1, column=2, sticky=(tk.N, tk.S))\n        #Configure rows and columns of the frame\n        self.search_frame.columnconfigure(0, weight=1)\n        self.search_frame.columnconfigure(1, weight=10)\n        self.search_frame.columnconfigure(1, weight=1)\n        self.search_frame.rowconfigure(0, weight=1)\n        self.search_frame.rowconfigure(1, weight = 10)\n        #########################################################\n        #                 Current Tool Frame                    #\n        #########################################################\n        #Create the elements of the current tool frame\n        self.current_tool_frame = ttk.Frame(overall_frame, padding='0.01i')\n        self.current_tool_lbl = ttk.Label(self.current_tool_frame, text=\"Current Tool: {}\".format(self.tool_name), justify=tk.LEFT)  # , font=(\"Helvetica\", 12, \"bold\") \n        self.view_code_button = ttk.Button(self.current_tool_frame, text=\"View Code\", width=12, command=self.view_code)\n        #Define layout of the frame\n        self.view_code_button.grid(row=0, column=1, sticky=tk.E)\n        self.current_tool_lbl.grid(row=0, column=0, sticky=tk.W)\n        self.current_tool_frame.grid(row=0, column=0, columnspan = 2, sticky=tk.NSEW)\n        #Configure rows and columns of the frame\n        self.current_tool_frame.columnconfigure(0, weight=1)\n        self.current_tool_frame.columnconfigure(1, weight=1)\n        #########################################################\n        #                      Args Frame                       #\n        #########################################################\n        # #Create the elements of the tool arguments frame\n        # self.arg_scroll = ttk.Scrollbar(overall_frame, orient='vertical')\n        # self.arg_canvas = tk.Canvas(overall_frame, bd=0, highlightthickness=0, yscrollcommand=self.arg_scroll.set)\n        # self.arg_scroll.config(command=self.arg_canvas.yview)    #self.arg_scroll scrolls over self.arg_canvas\n        # self.arg_scroll_frame = ttk.Frame(self.arg_canvas)    # create a frame inside the self.arg_canvas which will be scrolled with it\n        # self.arg_scroll_frame_id = self.arg_canvas.create_window(0, 0, window=self.arg_scroll_frame, anchor=\"nw\")\n        # #Define layout of the frame\n        # self.arg_scroll.grid(row = 1, column = 1, sticky = (tk.NS, tk.E))\n        # self.arg_canvas.grid(row = 1, column = 0, sticky = tk.NSEW)\n        # # reset the view\n        # self.arg_canvas.xview_moveto(0)\n        # self.arg_canvas.yview_moveto(0)\n        # #Add bindings\n        # self.arg_scroll_frame.bind('<Configure>', self.configure_arg_scroll_frame)\n        # self.arg_canvas.bind('<Configure>', self.configure_arg_canvas)\n        self.arg_scroll_frame = ttk.Frame(overall_frame, padding='0.0i')\n        self.arg_scroll_frame.grid(row=1, column=0, sticky=tk.NSEW)\n        self.arg_scroll_frame.columnconfigure(0, weight=1)\n        #########################################################\n        #                   Buttons Frame                       #\n        #########################################################\n        #Create the elements of the buttons frame\n        buttons_frame = ttk.Frame(overall_frame, padding='0.1i')\n        self.run_button = ttk.Button(buttons_frame, text=\"Run\", width=8, command=self.run_tool)\n        self.quit_button = ttk.Button(buttons_frame, text=\"Cancel\", width=8, command=self.cancel_operation)\n        self.help_button = ttk.Button(buttons_frame, text=\"Help\", width=8, command=self.tool_help_button)\n        #Define layout of the frame\n        self.run_button.grid(row=0, column=0)\n        self.quit_button.grid(row=0, column=1)\n        self.help_button.grid(row = 0, column = 2)\n        buttons_frame.grid(row=2, column=0, columnspan = 2, sticky=tk.E)\n        #########################################################\n        #                  Output Frame                      #\n        #########################################################                \n        #Create the elements of the output frame\n        output_frame = ttk.Frame(overall_frame)\n        outlabel = ttk.Label(output_frame, text=\"Output:\", justify=tk.LEFT)\n        self.out_text = ScrolledText(output_frame, width=63, height=15, wrap=tk.NONE, padx=7, pady=7, exportselection = 0)\n        output_scrollbar = ttk.Scrollbar(output_frame, orient=tk.HORIZONTAL, command = self.out_text.xview)\n        self.out_text['xscrollcommand'] = output_scrollbar.set\n        #Retrieve and insert the text for the current tool\n        k = wbt.tool_help(self.tool_name)   \n        self.out_text.insert(tk.END, k)\n        #Define layout of the frame\n        outlabel.grid(row=0, column=0, sticky=tk.NW)\n        self.out_text.grid(row=1, column=0, sticky=tk.NSEW)\n        output_frame.grid(row=3, column=0, columnspan = 2, sticky=(tk.NS, tk.E))\n        output_scrollbar.grid(row=2, column=0, sticky=(tk.W, tk.E))\n        #Configure rows and columns of the frame\n        self.out_text.columnconfigure(0, weight=1)\n        output_frame.columnconfigure(0, weight=1)\n        # Add the binding\n        if _platform == \"darwin\":\n            self.out_text.bind(\"<Command-Key-a>\", self.select_all)\n        else:\n            self.out_text.bind(\"<Control-Key-a>\", self.select_all)\n        #########################################################\n        #                  Progress Frame                       #\n        #########################################################        \n        #Create the elements of the progress frame\n        progress_frame = ttk.Frame(overall_frame, padding='0.1i')\n        self.progress_label = ttk.Label(progress_frame, text=\"Progress:\", justify=tk.LEFT)\n        self.progress_var = tk.DoubleVar()\n        self.progress = ttk.Progressbar(progress_frame, orient=\"horizontal\", variable=self.progress_var, length=200, maximum=100)\n        #Define layout of the frame\n        self.progress_label.grid(row=0, column=0, sticky=tk.E, padx=5)\n        self.progress.grid(row=0, column=1, sticky=tk.E)\n        progress_frame.grid(row=4, column=0, columnspan = 2, sticky=tk.SE)\n        #########################################################\n        #                  Tool Selection                       #\n        #########################################################        \n        # Select the appropriate tool, if specified, otherwise the first tool\n        self.tool_tree.focus(self.tool_name)\n        self.tool_tree.selection_set(self.tool_name)\n        self.tool_tree.event_generate(\"<<TreeviewSelect>>\")\n        #########################################################\n        #                       Menus                           #\n        #########################################################        \n        menubar = tk.Menu(self)\n\n        self.filemenu = tk.Menu(menubar, tearoff=0)\n        self.filemenu.add_command(label=\"Set Working Directory\", command=self.set_directory)\n        self.filemenu.add_command(label=\"Locate WhiteboxTools exe\", command=self.select_exe)\n        self.filemenu.add_command(label=\"Refresh Tools\", command=self.refresh_tools)\n\n        if wbt.get_verbose_mode():\n            self.filemenu.add_command(label=\"Do Not Print Tool Output\", command=self.update_verbose)\n        else:\n            self.filemenu.add_command(label=\"Print Tool Output\", command=self.update_verbose)\n\n        if wbt.get_compress_rasters():\n            self.filemenu.add_command(label=\"Do Not Compress Output TIFFs\", command=self.update_compress)\n        else:\n            self.filemenu.add_command(label=\"Compress Output TIFFs\", command=self.update_compress)\n\n        self.filemenu.add_command(label=\"Set Num. Processors\", command=self.set_procs)\n\n        self.filemenu.add_separator()\n        self.filemenu.add_command(label=\"Install a Whitebox Extension\", command=self.install_extension)\n        self.filemenu.add_separator()\n        self.filemenu.add_command(label=\"Exit\", command=self.quit)\n        menubar.add_cascade(label=\"File\", menu=self.filemenu)\n\n        editmenu = tk.Menu(menubar, tearoff=0)\n        editmenu.add_command(label=\"Cut\", command=lambda: self.focus_get().event_generate(\"<<Cut>>\"))\n        editmenu.add_command(label=\"Copy\", command=lambda: self.focus_get().event_generate(\"<<Copy>>\"))\n        editmenu.add_command(label=\"Paste\", command=lambda: self.focus_get().event_generate(\"<<Paste>>\"))\n        menubar.add_cascade(label=\"Edit \", menu=editmenu)\n\n        helpmenu = tk.Menu(menubar, tearoff=0)\n        helpmenu.add_command(label=\"About\", command=self.help)\n        helpmenu.add_command(label=\"License\", command=self.license)\n        menubar.add_cascade(label=\"Help \", menu=helpmenu)\n\n        self.master.config(menu=menubar)     \n\n    def update_verbose(self):\n        if wbt.get_verbose_mode():\n            wbt.set_verbose_mode(False)\n            self.filemenu.entryconfig(3, label = \"Print Tool Output\")\n        else:\n            wbt.set_verbose_mode(True)\n            self.filemenu.entryconfig(3, label = \"Do Not Print Tool Output\")\n\n    def update_compress(self):\n        if wbt.get_compress_rasters():\n            wbt.set_compress_rasters(False)\n            self.filemenu.entryconfig(3, label = \"Compress Output TIFFs\")\n        else:\n            wbt.set_compress_rasters(True)\n            self.filemenu.entryconfig(3, label = \"Do Not Compress Output TIFFs\")\n\n    def install_extension(self):\n        wbt.install_wbt_extension()\n        self.refresh_tools()\n\n    def get_toolboxes(self):\n        toolboxes = set()\n        for item in wbt.toolbox().splitlines():  # run wbt.toolbox with no tool specified--returns all\n            if item:\n                tb = item.split(\":\")[1].strip()\n                toolboxes.add(tb)\n        return sorted(toolboxes)\n\n    def sort_toolboxes(self):\n        self.upper_toolboxes = []\n        self.lower_toolboxes = []\n        for toolbox in self.toolbox_list:\n            if toolbox.find('/') == (-1):    #Does not contain a subtoolbox, i.e. does not contain '/'\n                self.upper_toolboxes.append(toolbox)    #add to both upper toolbox list and lower toolbox list\n                self.lower_toolboxes.append(toolbox)\n            else:    #Contains a subtoolbox\n                self.lower_toolboxes.append(toolbox)    #add to only the lower toolbox list  \n        self.upper_toolboxes = sorted(self.upper_toolboxes)    #sort both lists alphabetically\n        self.lower_toolboxes = sorted(self.lower_toolboxes)\n\n    def sort_tools_by_toolbox(self): \n        self.sorted_tools = [[] for i in range(len(self.lower_toolboxes))]    #One list for each lower toolbox\n        count = 1\n        for toolAndToolbox in self.tools_and_toolboxes.split('\\n'):\n            if toolAndToolbox.strip():\n                tool = toolAndToolbox.strip().split(':')[0].strip().replace(\"TIN\", \"Tin\").replace(\"KS\", \"Ks\").replace(\"FD\", \"Fd\")    #current tool\n                itemToolbox = toolAndToolbox.strip().split(':')[1].strip()    #current toolbox\n                index = 0\n                for toolbox in self.lower_toolboxes:    #find which toolbox the current tool belongs to\n                    if toolbox == itemToolbox:\n                        self.sorted_tools[index].append(tool)    #add current tool to list at appropriate index\n                        break\n                    index = index + 1\n                count = count + 1\n\n    def get_tools_list(self):\n        self.tools_list = []\n        selected_item = -1\n        for item in wbt.list_tools().keys():\n            if item:\n                value = to_camelcase(item).replace(\"TIN\", \"Tin\").replace(\"KS\", \"Ks\").replace(\"FD\", \"Fd\")    #format tool name\n                self.tools_list.append(value)    #add tool to list\n                if item == self.tool_name:    #update selected_item it tool found\n                    selected_item = len(self.tools_list) - 1\n        if selected_item == -1:    #set self.tool_name as default tool\n            selected_item = 0\n            self.tool_name = self.tools_list[0]\n\n    def tree_update_tool_help(self, event):    # read selection when tool selected from treeview then call self.update_tool_help\n        curItem = self.tool_tree.focus()\n        self.tool_name = self.tool_tree.item(curItem).get('text').replace(\"  \", \"\")\n        self.update_tool_help()\n\n    def search_update_tool_help(self, event):    # read selection when tool selected from search results then call self.update_tool_help\n        selection = self.search_results_listbox.curselection()\n        self.tool_name = self.search_results_listbox.get(selection[0])\n        self.update_tool_help()\n  \n    def update_tool_help(self):\n        self.out_text.delete('1.0', tk.END)\n        for widget in self.arg_scroll_frame.winfo_children():\n            widget.destroy()\n\n        k = wbt.tool_help(self.tool_name)\n        self.print_to_output(k)\n        # print(wbt.license(self.tool_name).lower())\n        if \"proprietary\" in wbt.license(self.tool_name).lower():\n            self.view_code_button[\"state\"] = \"disabled\"\n        else:\n            self.view_code_button[\"state\"] = \"enabled\"\n\n        j = json.loads(wbt.tool_parameters(self.tool_name))\n        param_num = 0\n        for p in j['parameters']:\n            json_str = json.dumps(\n                p, sort_keys=True, indent=2, separators=(',', ': '))\n            pt = p['parameter_type']\n            if 'ExistingFileOrFloat' in pt:\n                ff = FileOrFloat(json_str, self, self.arg_scroll_frame)\n                ff.grid(row=param_num, column=0, sticky=tk.NSEW)\n                param_num = param_num + 1\n            elif ('ExistingFile' in pt or 'NewFile' in pt or 'Directory' in pt):\n                fs = FileSelector(json_str, self, self.arg_scroll_frame)\n                fs.grid(row=param_num, column=0, sticky=tk.NSEW)\n                param_num = param_num + 1\n            elif 'FileList' in pt:\n                b = MultifileSelector(json_str, self, self.arg_scroll_frame)\n                b.grid(row=param_num, column=0, sticky=tk.W)\n                param_num = param_num + 1\n            elif 'Boolean' in pt:\n                b = BooleanInput(json_str, self.arg_scroll_frame)\n                b.grid(row=param_num, column=0, sticky=tk.W)\n                param_num = param_num + 1\n            elif 'OptionList' in pt:\n                b = OptionsInput(json_str, self.arg_scroll_frame)\n                b.grid(row=param_num, column=0, sticky=tk.W)\n                param_num = param_num + 1\n            elif ('Float' in pt or 'Integer' in pt or\n                  'Text' in pt or 'String' in pt or 'StringOrNumber' in pt or\n                  'StringList' in pt or 'VectorAttributeField' in pt):\n                b = DataInput(json_str, self.arg_scroll_frame)\n                b.grid(row=param_num, column=0, sticky=tk.NSEW)\n                param_num = param_num + 1\n            else:\n                messagebox.showinfo(\n                    \"Error\", \"Unsupported parameter type: {}.\".format(pt))\n        self.update_args_box()\n        self.out_text.see(\"%d.%d\" % (1, 0))\n\n    def update_toolbox_icon(self, event):\n        curItem = self.tool_tree.focus()\n        dict = self.tool_tree.item(curItem)    #retrieve the toolbox name\n        self.toolbox_name = dict.get('text'). replace(\"  \", \"\")    #delete the space between the icon and text\n        self.toolbox_open = dict.get('open')    #retrieve whether the toolbox is open or not\n        if self.toolbox_open == True:    #set image accordingly\n            self.tool_tree.item(self.toolbox_name, image = self.open_toolbox_icon)\n        else:\n            self.tool_tree.item(self.toolbox_name, image = self.closed_toolbox_icon)\n    \n    def update_search(self, event):\n        self.search_list = [] \n        self.search_string = self.search_text.get().lower()\n        self.search_results_listbox.delete(0, 'end') #empty the search results\n        num_results = 0\n        for tool in self.tools_list:  #search tool names\n            toolLower = tool.lower()\n            if toolLower.find(self.search_string) != (-1): #search string found within tool name\n                num_results = num_results + 1\n                self.search_results_listbox.insert(num_results, tool) #tool added to listbox and to search results string\n                self.search_list.append(tool)\n        index = 0\n        self.get_descriptions()\n        for description in self.descriptionList: #search tool descriptions\n            descriptionLower = description.lower()\n            if descriptionLower.find(self.search_string) != (-1): #search string found within tool description\n                found = 0\n                for item in self.search_list: # check if this tool is already in the listbox\n                    if self.tools_list[index] == item:\n                        found = 1\n                if found == 0:  # add to listbox\n                    num_results = num_results + 1\n                    self.search_results_listbox.insert(num_results, self.tools_list[index])    #tool added to listbox and to search results string\n            index = index + 1\n        self.search_frame['text'] = \"{} Tools Found\".format(num_results) #update search label\n\n    def get_descriptions(self):\n        self.descriptionList = []\n        tools = wbt.list_tools()\n        toolsItems = tools.items()\n        for t in toolsItems:\n            self.descriptionList.append(t[1])    #second entry in tool dictionary is the description\n     \n    # def configure_arg_scroll_frame(self, event):\n    #     # update the scrollbars to match the size of the inner frame\n    #     size = (self.arg_scroll_frame.winfo_reqwidth(), self.arg_scroll_frame.winfo_reqheight())\n    #     self.arg_canvas.config(scrollregion=\"0 0 %s %s\" % size)\n    #     if self.arg_scroll_frame.winfo_reqwidth() != self.arg_canvas.winfo_width():\n    #         # update the canvas's width to fit the inner frame\n    #         self.arg_canvas.config(width=self.arg_scroll_frame.winfo_reqwidth())\n\n    # def configure_arg_canvas(self, event):\n    #     if self.arg_scroll_frame.winfo_reqwidth() != self.arg_canvas.winfo_width():\n    #         # update the inner frame's width to fill the canvas\n    #         self.arg_canvas.itemconfigure(self.arg_scroll_frame_id, width=self.arg_canvas.winfo_width())\n    \n    def tool_help_button(self):\n        index = 0\n        found = False\n        #find toolbox corresponding to the current tool\n        for toolbox in self.lower_toolboxes:\n            for tool in self.sorted_tools[index]:\n                if tool == self.tool_name:\n                    self.toolbox_name = toolbox\n                    found = True\n                    break\n            if found:\n                break\n            index = index + 1\n        #change LiDAR to Lidar\n        if index == 10:\n            self.toolbox_name = to_camelcase(self.toolbox_name)\n        #format subtoolboxes as for URLs\n        self.toolbox_name = self.camel_to_snake(self.toolbox_name).replace('/', '').replace(' ', '') \n        #open the user manual section for the current tool\n        webbrowser.open_new_tab(\"https://www.whiteboxgeo.com/manual/wbt_book/available_tools/\" + self.toolbox_name + \".html#\" + self.tool_name)    \n    \n    def camel_to_snake(self, s):    # taken from tools_info.py\n        _underscorer1 = re.compile(r'(.)([A-Z][a-z]+)')\n        _underscorer2 = re.compile('([a-z0-9])([A-Z])')\n        subbed = _underscorer1.sub(r'\\1_\\2', s)\n        return _underscorer2.sub(r'\\1_\\2', subbed).lower()\n\n    def refresh_tools(self):\n        #refresh lists\n        self.tools_and_toolboxes = wbt.toolbox('')\n        self.sort_tools_by_toolbox()\n        self.get_tools_list()\n        #clear self.tool_tree\n        self.tool_tree.delete(*self.tool_tree.get_children())\n        #Add toolboxes and tools to treeview\n        index = 0\n        for toolbox in self.lower_toolboxes:\n            if toolbox.find('/') != (-1):    #toolboxes \n                self.tool_tree.insert(toolbox[:toolbox.find('/')], 0, text = \"  \" + toolbox[toolbox.find('/') + 1:], iid = toolbox[toolbox.find('/') + 1:], tags = 'toolbox', image = self.closed_toolbox_icon)\n                for tool in self.sorted_tools[index]:    #add tools within toolbox\n                    self.tool_tree.insert(toolbox[toolbox.find('/') + 1:], 'end', text = \"  \" + tool, tags = 'tool', iid = tool, image = self.tool_icon)       \n            else:    #subtoolboxes\n                self.tool_tree.insert('', 'end', text = \"  \" + toolbox, iid = toolbox, tags = 'toolbox', image = self.closed_toolbox_icon)                         \n                for tool in self.sorted_tools[index]:  #add tools within subtoolbox\n                    self.tool_tree.insert(toolbox, 'end', text = \"  \" + tool, iid = tool, tags = 'tool', image = self.tool_icon) \n            index = index + 1 \n        #Update label\n        self.tools_frame[\"text\"] = \"{} Available Tools\".format(len(self.tools_list))\n\n    #########################################################\n    #               Functions (original)                    #\n    #########################################################\n    def help(self):\n        self.print_to_output(wbt.version())\n\n    def license(self):\n        self.print_to_output(wbt.license())\n\n    def set_directory(self):\n        try:\n            self.working_dir = filedialog.askdirectory(initialdir=self.working_dir)\n            wbt.set_working_dir(self.working_dir)\n        except:\n            messagebox.showinfo(\n                \"Warning\", \"Could not set the working directory.\")\n\n    def set_procs(self):\n        try:\n            self.__max_procs = askinteger(\n                \"max_proc\", \n                \"Set the maximum number of processors used (-1 for all):\",\n                parent=self)\n            wbt.set_max_procs(self.__max_procs)\n        except:\n            messagebox.showinfo(\n                \"Warning\", \"Could not set the number of processors.\")\n\n    def select_exe(self):\n        try:\n            filename = filedialog.askopenfilename(initialdir=self.exe_path)\n            self.exe_path = path.dirname(path.abspath(filename))\n            wbt.set_whitebox_dir(self.exe_path)\n            self.refresh_tools()\n        except:\n            messagebox.showinfo(\n                \"Warning\", \"Could not find WhiteboxTools executable file.\")\n\n    def run_tool(self):\n        # wd_str = self.wd.get_value()\n        wbt.set_working_dir(self.working_dir)\n        # args = shlex.split(self.args_value.get())\n\n        args = []\n        for widget in self.arg_scroll_frame.winfo_children():\n            v = widget.get_value()\n            if v:\n                args.append(v)\n            elif not widget.optional:\n                messagebox.showinfo(\n                    \"Error\", \"Non-optional tool parameter not specified.\")\n                return\n\n        self.print_line_to_output(\"\")\n        # self.print_line_to_output(\"Tool arguments:{}\".format(args))\n        # self.print_line_to_output(\"\")\n        # Run the tool and check the return value for an error\n        if wbt.run_tool(self.tool_name, args, self.custom_callback) == 1:\n            print(\"Error running {}\".format(self.tool_name))\n\n        else:\n            self.run_button[\"text\"] = \"Run\"\n            self.progress_var.set(0)\n            self.progress_label['text'] = \"Progress:\"\n            self.progress.update_idletasks()\n\n    def print_to_output(self, value):\n        self.out_text.insert(tk.END, value)\n        self.out_text.see(tk.END)\n\n    def print_line_to_output(self, value):\n        self.out_text.insert(tk.END, value + \"\\n\")\n        self.out_text.see(tk.END)\n\n    def cancel_operation(self):\n        wbt.cancel_op = True\n        self.print_line_to_output(\"Cancelling operation...\")\n        self.progress.update_idletasks()\n\n    def view_code(self):\n        webbrowser.open_new_tab(wbt.view_code(self.tool_name).strip())\n    \n    def update_args_box(self):\n        s = \"\"\n        self.current_tool_lbl['text'] = \"Current Tool: {}\".format(\n            self.tool_name)\n        # self.spacer['width'] = width=(35-len(self.tool_name))\n        for item in wbt.tool_help(self.tool_name).splitlines():\n            if item.startswith(\"-\"):\n                k = item.split(\" \")\n                if \"--\" in k[1]:\n                    value = k[1].replace(\",\", \"\")\n                else:\n                    value = k[0].replace(\",\", \"\")\n\n                if \"flag\" in item.lower():\n                    s = s + value + \" \"\n                else:\n                    if \"file\" in item.lower():\n                        s = s + value + \"='{}' \"\n                    else:\n                        s = s + value + \"={} \"\n\n        # self.args_value.set(s.strip())\n\n    def custom_callback(self, value):\n        ''' A custom callback for dealing with tool output.\n        '''\n        if \"%\" in value:\n            try:\n                str_array = value.split(\" \")\n                label = value.replace(\n                    str_array[len(str_array) - 1], \"\").strip()\n                progress = float(\n                    str_array[len(str_array) - 1].replace(\"%\", \"\").strip())\n                self.progress_var.set(int(progress))\n                self.progress_label['text'] = label\n            except ValueError as e:\n                print(\"Problem converting parsed data into number: \", e)\n            except Exception as e:\n                print(e)\n        else:\n            self.print_line_to_output(value)\n\n        self.update()  # this is needed for cancelling and updating the progress bar\n\n    def select_all(self, event):\n        self.out_text.tag_add(tk.SEL, \"1.0\", tk.END)\n        self.out_text.mark_set(tk.INSERT, \"1.0\")\n        self.out_text.see(tk.INSERT)\n        return 'break'\n\nclass JsonPayload(object):\n    def __init__(self, j):\n        self.__dict__ = json.loads(j)\n\n\ndef main():\n    tool_name = None\n    if len(sys.argv) > 1:\n        tool_name = str(sys.argv[1])\n    wbr = WbRunner(tool_name)\n    wbr.mainloop()\n\n\nif __name__ == '__main__':\n    main()"
  },
  {
    "path": "WBT/whitebox_example.py",
    "content": "#!/usr/bin/env python\n''' This module provides examples of how to call the whitebox_tool script and the\nwhitebox-tools geospatial analysis library using Python code.\n'''\n\n# This script is part of the WhiteboxTools geospatial library.\n# Authors: Dr. John Lindsay\n# Created: November 28, 2017\n# Last Modified: Feb. 17, 2018\n# License: MIT\n\nfrom __future__ import print_function\nimport os\nimport sys\nfrom whitebox_tools import WhiteboxTools\nimport urllib.request\n\n\ndef main():\n    ''' main function\n    '''\n    try:\n        wbt = WhiteboxTools()\n\n        # Get the root directory of WhiteboxTools source code or executable file\n        root_dir = os.path.dirname(os.path.abspath(__file__))\n        # WhiteboxTools executable file name for MS Windows\n        wbt_win_bin = os.path.join(root_dir, \"whitebox_tools.exe\")\n        # WhiteboxTools executable file name for MacOS/Linux\n        wbt_linux_bin = os.path.join(root_dir, \"whitebox_tools\")\n\n        # If the WhiteboxTools executable file (whitbox_tools.exe) is in the same\n        # directory as this script, set wbt path to the current directory\n        # otherwise, set wbt path to (root_dir + \"/target/release/\")\n        if os.path.isfile(wbt_win_bin) or os.path.isfile(wbt_linux_bin):\n            wbt.set_whitebox_dir(root_dir)\n        else:\n            wbt.set_whitebox_dir(root_dir + \"/target/release/\")  # or simply wbt.exe_path = ...\n\n        # Set the working directory. This is the path to the folder containing the data,\n        # i.e. files sent to tools as input/output parameters. You don't need to set\n        # the working directory if you specify full path names as tool parameters.\n        wbt.work_dir = os.path.dirname(\n            os.path.abspath(__file__)) + \"/testdata/\"\n\n        # If test datasets do not exist, download them from the WhiteboxTools repo\n        if not os.path.exists(wbt.work_dir):\n            os.mkdir(wbt.work_dir)\n            dem_url = \"https://github.com/jblindsay/whitebox-tools/raw/master/testdata/DEM.tif\"\n            dep_url = \"https://github.com/jblindsay/whitebox-tools/raw/master/testdata/DEM.dep\"\n            urllib.request.urlretrieve(dem_url, \"testdata/DEM.tif\")\n            urllib.request.urlretrieve(dep_url, \"testdata/DEM.dep\")\n\n        # Sets verbose mode (True or False). Most tools will suppress output (e.g. updating\n        # progress) when verbose mode is False. The default is True\n        # wbt.set_verbose_mode(False) # or simply, wbt.verbose = False\n\n        # The most convenient way to run a tool is to use its associated method, e.g.:\n        if wbt.elev_percentile(\"DEM.tif\", \"output.tif\", 15, 15) != 0:\n            print(\"ERROR running tool\")\n\n        # You may also provide an optional custom callback for processing output from the\n        # tool. If you don't provide a callback, and verbose is set to True, tool output\n        # will simply be printed to the standard output. Also, notice that each tool has a\n        # convenience method. While internally, whitebox_tools.exe uses CamelCase (MeanFilter)\n        # to denote tool names, but the Python interface of whitebox_tools.py uses\n        # snake_case (mean_filter), according to Python style conventions.\n\n        # All of the convenience methods just call the 'run_tool' method, feeding it an\n        # args array. This is an alternative way of calling tools:\n        tool_name = \"elev_percentile\"\n        args = [\"--dem=\\\"DEM.dep\\\"\",\n                \"--output=\\\"DEV_101.dep\\\"\",\n                \"--filterx=101\"]\n\n        if wbt.run_tool(tool_name, args, my_callback) != 0:\n            print(\"ERROR running {}\".format(tool_name))\n\n        # Prints the whitebox-tools help...a listing of available commands\n        print(wbt.help())\n\n        # Prints the whitebox-tools license\n        print(wbt.license())\n\n        # Prints the whitebox-tools version\n        print(\"Version information: {}\".format(wbt.version()))\n\n        # List all available tools in whitebox-tools\n        print(wbt.list_tools())\n\n        # Lists tools with 'lidar' or 'LAS' in tool name or description.\n        print(wbt.list_tools(['lidar', 'LAS']))\n\n        # Print the help for a specific tool.\n        print(wbt.tool_help(\"ElevPercentile\"))\n        # Notice that tool names within WhiteboxTools.exe are CamelCase but\n        # you can also use snake_case here, e.g. print(wbt.tool_help(\"elev_percentile\"))\n\n    except:\n        print(\"Unexpected error:\", sys.exc_info()[0])\n        raise\n\n\ndef my_callback(out_str):\n    ''' Create a custom callback to process the text coming out of the tool.\n    If a callback is not provided, it will simply print the output stream.\n    A custom callback allows for processing of the output stream.\n    '''\n    try:\n        if not hasattr(my_callback, 'prev_line_progress'):\n            my_callback.prev_line_progress = False\n        if \"%\" in out_str:\n            str_array = out_str.split(\" \")\n            label = out_str.replace(str_array[len(str_array) - 1], \"\").strip()\n            progress = int(\n                str_array[len(str_array) - 1].replace(\"%\", \"\").strip())\n            if my_callback.prev_line_progress:\n                print('{0} {1}%'.format(label, progress), end=\"\\r\")\n            else:\n                my_callback.prev_line_progress = True\n                print(out_str)\n        elif \"error\" in out_str.lower():\n            print(\"ERROR: {}\".format(out_str))\n            my_callback.prev_line_progress = False\n        elif \"elapsed time (excluding i/o):\" in out_str.lower():\n            elapsed_time = ''.join(\n                ele for ele in out_str if ele.isdigit() or ele == '.')\n            units = out_str.lower().replace(\"elapsed time (excluding i/o):\",\n                                            \"\").replace(elapsed_time, \"\").strip()\n            print(\"Elapsed time: {0}{1}\".format(elapsed_time, units))\n            my_callback.prev_line_progress = False\n        else:\n            if callback.prev_line_progress:\n                print('\\n{0}'.format(out_str))\n                my_callback.prev_line_progress = False\n            else:\n                print(out_str)\n\n    except:\n        print(out_str)\n\n\nmain()\n"
  },
  {
    "path": "WBT/whitebox_tools.py",
    "content": "#!/usr/bin/env python3\n''' This file is intended to be a helper for running whitebox-tools plugins from a Python script.\nSee whitebox_example.py for an example of how to use it.\n'''\n\n# This script is part of the WhiteboxTools geospatial library.\n# Authors: Dr. John Lindsay\n# Created: 28/11/2017\n# Last Modified: 09/12/2019\n# License: MIT\n\nfrom __future__ import print_function\nimport zipfile\nimport shutil\nimport os\nfrom os import path\nimport sys\nimport platform\nimport re\nimport json\n# import shutil\n\nfrom subprocess import CalledProcessError, Popen, PIPE, STDOUT\nif sys.version_info.major == 2:\n    import urllib2 as urlopen\nelse:\n    import urllib.request as urlopen\n            \nrunning_windows = platform.system() == 'Windows'\n\nif running_windows:\n    from subprocess import STARTUPINFO, STARTF_USESHOWWINDOW\n\ndef default_callback(value):\n    ''' \n    A simple default callback that outputs using the print function. When\n    tools are called without providing a custom callback, this function\n    will be used to print to standard output.\n    '''\n    print(value)\n\n\ndef to_camelcase(name):\n    '''\n    Convert snake_case name to CamelCase name \n    '''\n    return ''.join(x.title() for x in name.split('_'))\n\n\ndef to_snakecase(name):\n    '''\n    Convert CamelCase name to snake_case name \n    '''\n    s1 = re.sub('(.)([A-Z][a-z]+)', r'\\1_\\2', name)\n    return re.sub('([a-z0-9])([A-Z])', r'\\1_\\2', s1).lower()\n\n\nclass WhiteboxTools(object):\n    ''' \n    An object for interfacing with the WhiteboxTools executable.\n    '''\n\n    def __init__(self):\n        if running_windows:\n            self.ext = '.exe'\n        else:\n            self.ext = ''\n        self.exe_name = \"whitebox_tools{}\".format(self.ext)\n        # self.exe_path = os.path.dirname(shutil.which(\n        #     self.exe_name) or path.dirname(path.abspath(__file__)))\n        # self.exe_path = os.path.dirname(os.path.join(os.path.realpath(__file__)))\n        self.exe_path = path.dirname(path.abspath(__file__))\n\n        self.work_dir = \"\"\n        self.verbose = True\n        self.__compress_rasters = False\n        self.__max_procs = -1\n\n        if os.path.isfile('settings.json'):\n            # read the settings.json file if it exists\n            with open('settings.json', 'r') as settings_file:\n                data = settings_file.read()\n\n            # parse file\n            settings = json.loads(data)\n            self.work_dir = str(settings['working_directory'])\n            self.verbose = str(settings['verbose_mode'])\n            self.__compress_rasters = settings['compress_rasters']\n            self.__max_procs = settings['max_procs']\n\n\n        self.cancel_op = False\n        self.default_callback = default_callback\n        self.start_minimized = False\n        \n    def set_whitebox_dir(self, path_str):\n        ''' \n        Sets the directory to the WhiteboxTools executable file.\n        '''\n        self.exe_path = path_str\n\n    def set_working_dir(self, path_str):\n        ''' \n        Sets the working directory, i.e. the directory in which\n        the data files are located. By setting the working \n        directory, tool input parameters that are files need only\n        specify the file name rather than the complete file path.\n        '''\n        self.work_dir = path.normpath(path_str)\n\n    def get_working_dir(self):\n        return self.work_dir\n\n    def get_verbose_mode(self):\n        return self.verbose\n\n    def set_verbose_mode(self, val=True):\n        ''' \n        Sets verbose mode. If verbose mode is False, tools will not\n        print output messages. Tools will frequently provide substantial\n        feedback while they are operating, e.g. updating progress for \n        various sub-routines. When the user has scripted a workflow\n        that ties many tools in sequence, this level of tool output\n        can be problematic. By setting verbose mode to False, these\n        messages are suppressed and tools run as background processes.\n        '''\n        self.verbose = val\n\n        try:\n            callback = self.default_callback\n\n            os.chdir(self.exe_path)\n            args2 = []\n            args2.append(\".\" + path.sep + self.exe_name)\n            \n            if self.verbose:\n                args2.append(\"-v\")\n            else:\n                args2.append(\"-v=false\")\n\n            proc = None\n\n            if running_windows and self.start_minimized == True:\n                si = STARTUPINFO()\n                si.dwFlags = STARTF_USESHOWWINDOW\n                si.wShowWindow = 7 #Set window minimized and not activated\n                proc = Popen(args2, shell=False, stdout=PIPE,\n                            stderr=STDOUT, bufsize=1, universal_newlines=True,\n                            startupinfo=si)\n            else:\n                proc = Popen(args2, shell=False, stdout=PIPE,\n                            stderr=STDOUT, bufsize=1, universal_newlines=True)\n\n            while proc is not None:\n                line = proc.stdout.readline()\n                sys.stdout.flush()\n                if line != '':\n                    if not self.cancel_op:\n                        callback(line.strip())\n                    else:\n                        self.cancel_op = False\n                        proc.terminate()\n                        return 2\n\n                else:\n                    break\n\n            return 0\n        except (OSError, ValueError, CalledProcessError) as err:\n            callback(str(err))\n            return 1\n\n    def set_default_callback(self, callback_func):\n        '''\n        Sets the default callback used for handling tool text outputs.\n        '''\n        self.default_callback = callback_func\n\n    def set_compress_rasters(self, val=True):\n        ''' \n        Sets the flag used by WhiteboxTools to determine whether to use compression for output rasters.\n        '''\n        self.__compress_rasters = val\n\n        try:\n            callback = self.default_callback\n\n            os.chdir(self.exe_path)\n            args2 = []\n            args2.append(\".\" + path.sep + self.exe_name)\n            \n            if self.__compress_rasters:\n                args2.append(\"--compress_rasters=true\")\n            else:\n                args2.append(\"--compress_rasters=false\")\n\n            proc = None\n\n            if running_windows and self.start_minimized == True:\n                si = STARTUPINFO()\n                si.dwFlags = STARTF_USESHOWWINDOW\n                si.wShowWindow = 7 #Set window minimized and not activated\n                proc = Popen(args2, shell=False, stdout=PIPE,\n                            stderr=STDOUT, bufsize=1, universal_newlines=True,\n                            startupinfo=si)\n            else:\n                proc = Popen(args2, shell=False, stdout=PIPE,\n                            stderr=STDOUT, bufsize=1, universal_newlines=True)\n\n            while proc is not None:\n                line = proc.stdout.readline()\n                sys.stdout.flush()\n                if line != '':\n                    if not self.cancel_op:\n                        callback(line.strip())\n                    else:\n                        self.cancel_op = False\n                        proc.terminate()\n                        return 2\n\n                else:\n                    break\n\n            return 0\n        except (OSError, ValueError, CalledProcessError) as err:\n            callback(str(err))\n            return 1\n    \n    def get_compress_rasters(self):\n        return self.__compress_rasters\n        \n    def set_max_procs(self, val=-1):\n        ''' \n        Sets the flag used by WhiteboxTools to determine whether to use compression for output rasters.\n        '''\n        self.__max_procs = val\n\n        try:\n            callback = self.default_callback\n\n            os.chdir(self.exe_path)\n            args2 = []\n            args2.append(\".\" + path.sep + self.exe_name)\n            \n            args2.append(\"--max_procs={}\".format(val))\n            proc = None\n\n            if running_windows and self.start_minimized == True:\n                si = STARTUPINFO()\n                si.dwFlags = STARTF_USESHOWWINDOW\n                si.wShowWindow = 7 # Set window minimized and not activated\n                proc = Popen(args2, shell=False, stdout=PIPE,\n                            stderr=STDOUT, bufsize=1, universal_newlines=True,\n                            startupinfo=si)\n            else:\n                proc = Popen(args2, shell=False, stdout=PIPE,\n                            stderr=STDOUT, bufsize=1, universal_newlines=True)\n\n            while proc is not None:\n                line = proc.stdout.readline()\n                sys.stdout.flush()\n                if line != '':\n                    if not self.cancel_op:\n                        callback(line.strip())\n                    else:\n                        self.cancel_op = False\n                        proc.terminate()\n                        return 2\n\n                else:\n                    break\n\n            return 0\n        except (OSError, ValueError, CalledProcessError) as err:\n            callback(str(err))\n            return 1\n    \n    def get_max_procs(self):\n        return self.__max_procs\n    \n    def run_tool(self, tool_name, args, callback=None):\n        ''' \n        Runs a tool and specifies tool arguments.\n        Returns 0 if completes without error.\n        Returns 1 if error encountered (details are sent to callback).\n        Returns 2 if process is cancelled by user.\n        '''\n        try:\n            if callback is None:\n                callback = self.default_callback\n\n            os.chdir(self.exe_path)\n            args2 = []\n            args2.append(\".\" + path.sep + self.exe_name)\n            args2.append(\"--run=\\\"{}\\\"\".format(to_camelcase(tool_name)))\n\n            if self.work_dir.strip() != \"\":\n                args2.append(\"--wd=\\\"{}\\\"\".format(self.work_dir))\n\n            for arg in args:\n                args2.append(arg)\n\n            # args_str = args_str[:-1]\n            # a.append(\"--args=\\\"{}\\\"\".format(args_str))\n\n            if self.verbose:\n                args2.append(\"-v\")\n            else:\n                args2.append(\"-v=false\")\n\n            if self.__compress_rasters:\n                args2.append(\"--compress_rasters=True\")\n            else:\n                args2.append(\"--compress_rasters=False\")\n\n            if self.verbose:\n                cl = \" \".join(args2)\n                callback(cl.strip() + \"\\n\")\n\n            proc = None\n\n            if running_windows and self.start_minimized == True:\n                si = STARTUPINFO()\n                si.dwFlags = STARTF_USESHOWWINDOW\n                si.wShowWindow = 7 #Set window minimized and not activated\n                proc = Popen(args2, shell=False, stdout=PIPE,\n                            stderr=STDOUT, bufsize=1, universal_newlines=True,\n                            startupinfo=si)\n            else:\n                proc = Popen(args2, shell=False, stdout=PIPE,\n                            stderr=STDOUT, bufsize=1, universal_newlines=True)\n\n            while proc is not None:\n                line = proc.stdout.readline()\n                sys.stdout.flush()\n                if line != '':\n                    if not self.cancel_op:\n                        if self.verbose:\n                            callback(line.strip())\n                    else:\n                        self.cancel_op = False\n                        proc.terminate()\n                        return 2\n                else:\n                    break\n\n            return 0\n        except (OSError, ValueError, CalledProcessError) as err:\n            callback(str(err))\n            return 1\n\n    def help(self):\n        ''' \n        Retrieves the help description for WhiteboxTools.\n        '''\n        try:\n            os.chdir(self.exe_path)\n            args = []\n            args.append(\".\" + os.path.sep + self.exe_name)\n            args.append(\"-h\")\n\n            proc = Popen(args, shell=False, stdout=PIPE,\n                         stderr=STDOUT, bufsize=1, universal_newlines=True)\n            ret = \"\"\n            while True:\n                line = proc.stdout.readline()\n                if line != '':\n                    ret += line\n                else:\n                    break\n\n            return ret\n        except (OSError, ValueError, CalledProcessError) as err:\n            return err\n\n    def license(self, toolname=None):\n        ''' \n        Retrieves the license information for WhiteboxTools.\n        '''\n        try:\n            os.chdir(self.exe_path)\n            args = []\n            args.append(\".\" + os.path.sep + self.exe_name)\n            args.append(\"--license\")\n            if toolname is not None:\n                args.append(\"={}\".format(toolname))\n            proc = Popen(args, shell=False, stdout=PIPE,\n                         stderr=STDOUT, bufsize=1, universal_newlines=True)\n            ret = \"\"\n            while True:\n                line = proc.stdout.readline()\n                if line != '':\n                    ret += line\n                else:\n                    break\n\n            return ret\n        except (OSError, ValueError, CalledProcessError) as err:\n            return err\n\n    def version(self):\n        ''' \n        Retrieves the version information for WhiteboxTools.\n        '''\n        try:\n            os.chdir(self.exe_path)\n            args = []\n            args.append(\".\" + os.path.sep + self.exe_name)\n            args.append(\"--version\")\n\n            proc = Popen(args, shell=False, stdout=PIPE,\n                         stderr=STDOUT, bufsize=1, universal_newlines=True)\n            ret = \"\"\n            while True:\n                line = proc.stdout.readline()\n                if line != '':\n                    ret += line\n                else:\n                    break\n\n            return ret\n        except (OSError, ValueError, CalledProcessError) as err:\n            return err\n\n    def tool_help(self, tool_name=''):\n        ''' \n        Retrieves the help description for a specific tool.\n        '''\n        try:\n            os.chdir(self.exe_path)\n            args = []\n            args.append(\".\" + os.path.sep + self.exe_name)\n            args.append(\"--toolhelp={}\".format(to_camelcase(tool_name)))\n\n            proc = Popen(args, shell=False, stdout=PIPE,\n                         stderr=STDOUT, bufsize=1, universal_newlines=True)\n            ret = \"\"\n            while True:\n                line = proc.stdout.readline()\n                if line != '':\n                    ret += line\n                else:\n                    break\n\n            return ret\n        except (OSError, ValueError, CalledProcessError) as err:\n            return err\n\n    def tool_parameters(self, tool_name):\n        ''' \n        Retrieves the tool parameter descriptions for a specific tool.\n        '''\n        try:\n            os.chdir(self.exe_path)\n            args = []\n            args.append(\".\" + os.path.sep + self.exe_name)\n            args.append(\"--toolparameters={}\".format(to_camelcase(tool_name)))\n\n            proc = Popen(args, shell=False, stdout=PIPE,\n                         stderr=STDOUT, bufsize=1, universal_newlines=True)\n            ret = \"\"\n            while True:\n                line = proc.stdout.readline()\n                if line != '':\n                    ret += line\n                else:\n                    break\n\n            return ret\n        except (OSError, ValueError, CalledProcessError) as err:\n            return err\n\n    def toolbox(self, tool_name=''):\n        ''' \n        Retrieve the toolbox for a specific tool.\n        '''\n        try:\n            os.chdir(self.exe_path)\n            args = []\n            args.append(\".\" + os.path.sep + self.exe_name)\n            args.append(\"--toolbox={}\".format(to_camelcase(tool_name)))\n\n            proc = Popen(args, shell=False, stdout=PIPE,\n                         stderr=STDOUT, bufsize=1, universal_newlines=True)\n            ret = \"\"\n            while True:\n                line = proc.stdout.readline()\n                if line != '':\n                    ret += line\n                else:\n                    break\n\n            return ret\n        except (OSError, ValueError, CalledProcessError) as err:\n            return err\n\n    def view_code(self, tool_name):\n        ''' \n        Opens a web browser to view the source code for a specific tool\n        on the projects source code repository.\n        '''\n        try:\n            os.chdir(self.exe_path)\n            args = []\n            args.append(\".\" + os.path.sep + self.exe_name)\n            args.append(\"--viewcode={}\".format(to_camelcase(tool_name)))\n\n            proc = Popen(args, shell=False, stdout=PIPE,\n                         stderr=STDOUT, bufsize=1, universal_newlines=True)\n            ret = \"\"\n            while True:\n                line = proc.stdout.readline()\n                if line != '':\n                    ret += line\n                else:\n                    break\n\n            return ret\n        except (OSError, ValueError, CalledProcessError) as err:\n            return err\n\n    def list_tools(self, keywords=[]):\n        ''' \n        Lists all available tools in WhiteboxTools.\n        '''\n        try:\n            os.chdir(self.exe_path)\n            args = []\n            args.append(\".\" + os.path.sep + self.exe_name)\n            args.append(\"--listtools\")\n            if len(keywords) > 0:\n                for kw in keywords:\n                    args.append(kw)\n\n            proc = Popen(args, shell=False, stdout=PIPE,\n                         stderr=STDOUT, bufsize=1, universal_newlines=True)\n            ret = {}\n            line = proc.stdout.readline()  # skip number of available tools header\n            while True:\n                line = proc.stdout.readline()\n                if line != '':\n                    if line.strip() != '':\n                        name, descr = line.split(':')\n                        ret[to_snakecase(name.strip())] = descr.strip()\n                else:\n                    break\n\n            return ret\n        except (OSError, ValueError, CalledProcessError) as err:\n            return err\n\n    def install_wbt_extension(self, ext_name=\"\"):\n        try:\n            if len(ext_name) == 0:\n                ext_name = input(\n'''Which extension would you like to install? (gte/lidar/dem/agri) ''')\n\n            # Figure out the appropriate URL to download the extension binary from.\n            url = \"https://www.whiteboxgeo.com/GTE_Windows/GeneralToolsetExtension_win.zip\" # default\n            unzipped_dir_name = \"GeneralToolsetExtension\"\n            if \"agri\" in ext_name.lower():\n                if platform.system() == 'Windows':\n                    url = \"https://www.whiteboxgeo.com/AgricultureToolset/AgricultureToolset_win.zip\"\n                elif platform.system() == 'Darwin':\n                    url = \"https://www.whiteboxgeo.com/AgricultureToolset/AgricultureToolset_MacOS_Intel.zip\"\n                elif platform.system() == 'Linux':\n                    url = \"https://www.whiteboxgeo.com/AgricultureToolset/AgricultureToolset_linux.zip\"\n                \n                unzipped_dir_name = \"AgricultureToolset\"\n            elif \"dem\" in ext_name.lower():\n                if platform.system() == 'Windows':\n                    url = \"https://www.whiteboxgeo.com/DemAndSpatialHydrologyToolset/DemAndSpatialHydrologyToolset_win.zip\"\n                elif platform.system() == 'Darwin':\n                    url = \"https://www.whiteboxgeo.com/DemAndSpatialHydrologyToolset/DemAndSpatialHydrologyToolset_MacOS_Intel.zip\"\n                elif platform.system() == 'Linux':\n                    url = \"https://www.whiteboxgeo.com/DemAndSpatialHydrologyToolset/DemAndSpatialHydrologyToolset_linux.zip\"\n\n                unzipped_dir_name = \"DemAndSpatialHydrologyToolset\"\n            elif \"lidar\" in ext_name.lower():\n                if platform.system() == 'Windows':\n                    url = \"https://www.whiteboxgeo.com/LidarAndRemoteSensingToolset/LidarAndRemoteSensingToolset_win.zip\"\n                elif platform.system() == 'Darwin':\n                    url = \"https://www.whiteboxgeo.com/LidarAndRemoteSensingToolset/LidarAndRemoteSensingToolset_MacOS_Intel.zip\"\n                elif platform.system() == 'Linux':\n                    url = \"https://www.whiteboxgeo.com/LidarAndRemoteSensingToolset/LidarAndRemoteSensingToolset_linux.zip\"\n                \n                unzipped_dir_name = \"LidarAndRemoteSensingToolset\"\n            else: # default to the general toolset\n                if \"gte\" not in ext_name.lower():\n                    print(\"Warning: Unrecognized extension ext_name {}. Installing the GTE instead...\".format(ext_name))\n\n                if platform.system() == 'Darwin':\n                    url = \"https://www.whiteboxgeo.com/GTE_Darwin/GeneralToolsetExtension_MacOS_Intel.zip\"\n                elif platform.system() == 'Linux':\n                    url = \"https://www.whiteboxgeo.com/GTE_Linux/GeneralToolsetExtension_linux.zip\"\n\n            # Download the extension binary\n            print(\"Downloading extension plugins...\")\n            compressed_plugins_file = urlopen.urlopen(url)\n\n            # Save it to a zip then decompress it and move the files to the plugins folder.\n            print(\"Installing extension plugins...\")\n            with open('./compressed_plugins.zip','wb') as output:\n                output.write(compressed_plugins_file.read())\n\n            if not os.path.exists('./plugins'):\n                os.makedirs('./plugins')\n\n            with zipfile.ZipFile('./compressed_plugins.zip', 'r') as zip_ref:\n                zip_ref.extractall('./')\n\n            for entry in os.scandir('./{}'.format(unzipped_dir_name)):\n                new_path = entry.path.replace('{}'.format(unzipped_dir_name), 'plugins')\n                os.replace(entry.path, new_path)\n                if \".json\" not in new_path and platform.system() != \"Windows\":\n                    os.system(\"chmod 755 \" + new_path) # grant executable permission\n\n            # Remove the unzipped directory, which isn't needed anymore.\n            if os.path.exists('./{}'.format(unzipped_dir_name)):\n                shutil.rmtree('./{}'.format(unzipped_dir_name))\n\n            # Get the updated Python API, so that they can use any new extension tools that\n            # have been released since the last open-core release from Python.\n            print(\"Updating WBT Python API...\")\n            \n            url = \"https://raw.githubusercontent.com/jblindsay/whitebox-tools/master/whitebox_tools.py\"\n            with urlopen.urlopen(url) as f:\n                api_text = f.read().decode('utf-8')\n                with open('./whitebox_tools.py', 'w') as output:\n                    output.write(api_text)\n\n            if \"agri\" in ext_name.lower():\n                print(\"The Whitebox Agriculture Toolset Extension has been installed!\")\n            elif \"dem\" in ext_name.lower():\n                print(\"The Whitebox DEM and Spatial Hydrology Toolset Extension has been installed!\")\n            elif \"lidar\" in ext_name.lower():\n                print(\"The Whitebox DEM and LiDAR and Remote Sensing Toolset Extension has been installed!\")\n            else:\n                print(\"The Whitebox General Toolset Extension (GTE) has been installed!\")\n\n            print(\n'''\nYou will need to activate a license before using this extension. If you do \nnot currently have a valid activation key, you may purchase one by visiting \nhttps://www.whiteboxgeo.com/extension-pricing/''')\n            # Does the user want to register an activation key for this extension?\n            reply = input(\"\\nWould you like to activate a license key for the extension now? (Y/n) \")\n\n            if \"y\" in reply.lower():\n                self.activate_license()\n            else:\n                print(\n'''\nOkay, that's it for now.\n''')\n\n        except Exception as e:\n            print(\"Unexpected error:\", e)\n            print(\"Please contact support@whiteboxgeo.com if you continue to experience issues.\")\n            raise\n\n    def activate_license(self):\n        try:\n            if platform.system() == 'Windows':\n                os.system(\"plugins\\\\register_license.exe\")\n            else:\n                os.system(\"./plugins/register_license\")\n        except:\n            print(\"Unexpected error:\", sys.exc_info()[0])\n            print(\"Please contact support@whiteboxgeo.com if you continue to experience issues.\")\n            raise\n\n    ########################################################################\n    # The following methods are convenience methods for each available tool.\n    # This needs updating whenever new tools are added to the WhiteboxTools\n    # library. They can be generated automatically using the\n    # whitebox_plugin_generator.py script. It would also be possible to\n    # discover plugins at runtime and monkey-patch their methods using\n    # MethodType. However, this would not be as useful since it would\n    # restrict the ability for text editors and IDEs to use autocomplete.\n    ########################################################################\n\n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    \n    ##############\n    # Data Tools #\n    ##############\n\n    def add_point_coordinates_to_table(self, i, callback=None):\n        \"\"\"Modifies the attribute table of a point vector by adding fields containing each point's X and Y coordinates.\n\n        Keyword arguments:\n\n        i -- Input vector Points file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('add_point_coordinates_to_table', args, callback) # returns 1 if error\n\n    def clean_vector(self, i, output, callback=None):\n        \"\"\"Removes null features and lines/polygons with fewer than the required number of vertices.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('clean_vector', args, callback) # returns 1 if error\n\n    def convert_nodata_to_zero(self, i, output, callback=None):\n        \"\"\"Converts nodata values in a raster to zero.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('convert_nodata_to_zero', args, callback) # returns 1 if error\n\n    def convert_raster_format(self, i, output, callback=None):\n        \"\"\"Converts raster data from one format to another.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('convert_raster_format', args, callback) # returns 1 if error\n\n    def csv_points_to_vector(self, i, output, xfield=0, yfield=1, epsg=None, callback=None):\n        \"\"\"Converts a CSV text file to vector points.\n\n        Keyword arguments:\n\n        i -- Input CSV file (i.e. source of data to be imported). \n        output -- Output vector file. \n        xfield -- X field number (e.g. 0 for first field). \n        yfield -- Y field number (e.g. 1 for second field). \n        epsg -- EPSG projection (e.g. 2958). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--xfield={}\".format(xfield))\n        args.append(\"--yfield={}\".format(yfield))\n        if epsg is not None: args.append(\"--epsg='{}'\".format(epsg))\n        return self.run_tool('csv_points_to_vector', args, callback) # returns 1 if error\n\n    def export_table_to_csv(self, i, output, headers=True, callback=None):\n        \"\"\"Exports an attribute table to a CSV text file.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output csv file. \n        headers -- Export field names as file header?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if headers: args.append(\"--headers\")\n        return self.run_tool('export_table_to_csv', args, callback) # returns 1 if error\n\n    def fix_dangling_arcs(self, i, output, dist=\"\", callback=None):\n        \"\"\"This tool fixes undershot and overshot arcs, two common topological errors, in an input vector lines file.\n\n        Keyword arguments:\n\n        i -- Name of the input lines vector file. \n        output -- Name of the output lines vector file. \n        dist -- Snap distance, in xy units (metres). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--dist={}\".format(dist))\n        return self.run_tool('fix_dangling_arcs', args, callback) # returns 1 if error\n\n    def join_tables(self, input1, pkey, input2, fkey, import_field=None, callback=None):\n        \"\"\"Merge a vector's attribute table with another table based on a common field.\n\n        Keyword arguments:\n\n        input1 -- Input primary vector file (i.e. the table to be modified). \n        pkey -- Primary key field. \n        input2 -- Input foreign vector file (i.e. source of data to be imported). \n        fkey -- Foreign key field. \n        import_field -- Imported field (all fields will be imported if not specified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--pkey='{}'\".format(pkey))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--fkey='{}'\".format(fkey))\n        if import_field is not None: args.append(\"--import_field='{}'\".format(import_field))\n        return self.run_tool('join_tables', args, callback) # returns 1 if error\n\n    def lines_to_polygons(self, i, output, callback=None):\n        \"\"\"Converts vector polylines to polygons.\n\n        Keyword arguments:\n\n        i -- Input vector line file. \n        output -- Output vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('lines_to_polygons', args, callback) # returns 1 if error\n\n    def merge_table_with_csv(self, i, pkey, csv, fkey, import_field=None, callback=None):\n        \"\"\"Merge a vector's attribute table with a table contained within a CSV text file.\n\n        Keyword arguments:\n\n        i -- Input primary vector file (i.e. the table to be modified). \n        pkey -- Primary key field. \n        csv -- Input CSV file (i.e. source of data to be imported). \n        fkey -- Foreign key field. \n        import_field -- Imported field (all fields will be imported if not specified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--pkey='{}'\".format(pkey))\n        args.append(\"--csv='{}'\".format(csv))\n        args.append(\"--fkey='{}'\".format(fkey))\n        if import_field is not None: args.append(\"--import_field='{}'\".format(import_field))\n        return self.run_tool('merge_table_with_csv', args, callback) # returns 1 if error\n\n    def merge_vectors(self, inputs, output, callback=None):\n        \"\"\"Combines two or more input vectors of the same ShapeType creating a single, new output vector.\n\n        Keyword arguments:\n\n        inputs -- Input vector files. \n        output -- Output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('merge_vectors', args, callback) # returns 1 if error\n\n    def modify_no_data_value(self, i, new_value=\"-32768.0\", callback=None):\n        \"\"\"Modifies nodata values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        new_value -- New NoData value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--new_value={}\".format(new_value))\n        return self.run_tool('modify_no_data_value', args, callback) # returns 1 if error\n\n    def multi_part_to_single_part(self, i, output, exclude_holes=True, callback=None):\n        \"\"\"Converts a vector file containing multi-part features into a vector containing only single-part features.\n\n        Keyword arguments:\n\n        i -- Input vector line or polygon file. \n        output -- Output vector line or polygon file. \n        exclude_holes -- Exclude hole parts from the feature splitting? (holes will continue to belong to their features in output.). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if exclude_holes: args.append(\"--exclude_holes\")\n        return self.run_tool('multi_part_to_single_part', args, callback) # returns 1 if error\n\n    def new_raster_from_base(self, base, output, value=\"nodata\", data_type=\"float\", cell_size=None, callback=None):\n        \"\"\"Creates a new raster using a base image.\n\n        Keyword arguments:\n\n        base -- Input base raster file. \n        output -- Output raster file. \n        value -- Constant value to fill raster with; either 'nodata' or numeric value. \n        data_type -- Output raster data type; options include 'double' (64-bit), 'float' (32-bit), and 'integer' (signed 16-bit) (default is 'float'). \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--base='{}'\".format(base))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--value={}\".format(value))\n        args.append(\"--data_type={}\".format(data_type))\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        return self.run_tool('new_raster_from_base', args, callback) # returns 1 if error\n\n    def polygons_to_lines(self, i, output, callback=None):\n        \"\"\"Converts vector polygons to polylines.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        output -- Output vector lines file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('polygons_to_lines', args, callback) # returns 1 if error\n\n    def print_geo_tiff_tags(self, i, callback=None):\n        \"\"\"Prints the tags within a GeoTIFF.\n\n        Keyword arguments:\n\n        i -- Input GeoTIFF file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('print_geo_tiff_tags', args, callback) # returns 1 if error\n\n    def raster_to_vector_lines(self, i, output, callback=None):\n        \"\"\"Converts a raster lines features into a vector of the POLYLINE shapetype.\n\n        Keyword arguments:\n\n        i -- Input raster lines file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('raster_to_vector_lines', args, callback) # returns 1 if error\n\n    def raster_to_vector_points(self, i, output, callback=None):\n        \"\"\"Converts a raster dataset to a vector of the POINT shapetype.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output vector points file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('raster_to_vector_points', args, callback) # returns 1 if error\n\n    def raster_to_vector_polygons(self, i, output, callback=None):\n        \"\"\"Converts a raster dataset to a vector of the POLYGON shapetype.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output vector polygons file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('raster_to_vector_polygons', args, callback) # returns 1 if error\n\n    def reinitialize_attribute_table(self, i, callback=None):\n        \"\"\"Reinitializes a vector's attribute table deleting all fields but the feature ID (FID).\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('reinitialize_attribute_table', args, callback) # returns 1 if error\n\n    def remove_polygon_holes(self, i, output, callback=None):\n        \"\"\"Removes holes within the features of a vector polygon file.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        output -- Output vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('remove_polygon_holes', args, callback) # returns 1 if error\n\n    def remove_raster_polygon_holes(self, i, output, threshold=3, use_diagonals=True, callback=None):\n        \"\"\"Removes polygon holes, or 'donut-holes', from raster polygons.\n\n        Keyword arguments:\n\n        i -- Name of the input raster image file. \n        output -- Name of the output raster file. \n        threshold -- Maximum size of removed holes, in grid cells. Blank for no threshold, i.e. remove all holes. \n        use_diagonals -- Use diagonal neighbours during clumping operation. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--threshold={}\".format(threshold))\n        if use_diagonals: args.append(\"--use_diagonals\")\n        return self.run_tool('remove_raster_polygon_holes', args, callback) # returns 1 if error\n\n    def set_nodata_value(self, i, output, back_value=0.0, callback=None):\n        \"\"\"Assign the NoData value for an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        back_value -- Background value to set to nodata. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--back_value={}\".format(back_value))\n        return self.run_tool('set_nodata_value', args, callback) # returns 1 if error\n\n    def single_part_to_multi_part(self, i, output, field=None, callback=None):\n        \"\"\"Converts a vector file containing multi-part features into a vector containing only single-part features.\n\n        Keyword arguments:\n\n        i -- Input vector line or polygon file. \n        field -- Grouping ID field name in attribute table. \n        output -- Output vector line or polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if field is not None: args.append(\"--field='{}'\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('single_part_to_multi_part', args, callback) # returns 1 if error\n\n    def vector_lines_to_raster(self, i, output, field=\"FID\", nodata=True, cell_size=None, base=None, callback=None):\n        \"\"\"Converts a vector containing polylines into a raster.\n\n        Keyword arguments:\n\n        i -- Input vector lines file. \n        field -- Input field name in attribute table. \n        output -- Output raster file. \n        nodata -- Background value to set to NoData. Without this flag, it will be set to 0.0. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field={}\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        if nodata: args.append(\"--nodata\")\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        return self.run_tool('vector_lines_to_raster', args, callback) # returns 1 if error\n\n    def vector_points_to_raster(self, i, output, field=\"FID\", assign=\"last\", nodata=True, cell_size=None, base=None, callback=None):\n        \"\"\"Converts a vector containing points into a raster.\n\n        Keyword arguments:\n\n        i -- Input vector Points file. \n        field -- Input field name in attribute table. \n        output -- Output raster file. \n        assign -- Assignment operation, where multiple points are in the same grid cell; options include 'first', 'last' (default), 'min', 'max', 'sum', 'number'. \n        nodata -- Background value to set to NoData. Without this flag, it will be set to 0.0. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field={}\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--assign={}\".format(assign))\n        if nodata: args.append(\"--nodata\")\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        return self.run_tool('vector_points_to_raster', args, callback) # returns 1 if error\n\n    def vector_polygons_to_raster(self, i, output, field=\"FID\", nodata=True, cell_size=None, base=None, callback=None):\n        \"\"\"Converts a vector containing polygons into a raster.\n\n        Keyword arguments:\n\n        i -- Input vector polygons file. \n        field -- Input field name in attribute table. \n        output -- Output raster file. \n        nodata -- Background value to set to NoData. Without this flag, it will be set to 0.0. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field={}\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        if nodata: args.append(\"--nodata\")\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        return self.run_tool('vector_polygons_to_raster', args, callback) # returns 1 if error\n\n    ################\n    # GIS Analysis #\n    ################\n\n    def aggregate_raster(self, i, output, agg_factor=2, type=\"mean\", callback=None):\n        \"\"\"Aggregates a raster to a lower resolution.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        agg_factor -- Aggregation factor, in pixels. \n        type -- Statistic used to fill output pixels. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--agg_factor={}\".format(agg_factor))\n        args.append(\"--type={}\".format(type))\n        return self.run_tool('aggregate_raster', args, callback) # returns 1 if error\n\n    def block_maximum_gridding(self, i, field, output, use_z=False, cell_size=None, base=None, callback=None):\n        \"\"\"Creates a raster grid based on a set of vector points and assigns grid values using a block maximum scheme.\n\n        Keyword arguments:\n\n        i -- Input vector Points file. \n        field -- Input field name in attribute table. \n        use_z -- Use z-coordinate instead of field?. \n        output -- Output raster file. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field='{}'\".format(field))\n        if use_z: args.append(\"--use_z\")\n        args.append(\"--output='{}'\".format(output))\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        return self.run_tool('block_maximum_gridding', args, callback) # returns 1 if error\n\n    def block_minimum_gridding(self, i, field, output, use_z=False, cell_size=None, base=None, callback=None):\n        \"\"\"Creates a raster grid based on a set of vector points and assigns grid values using a block minimum scheme.\n\n        Keyword arguments:\n\n        i -- Input vector Points file. \n        field -- Input field name in attribute table. \n        use_z -- Use z-coordinate instead of field?. \n        output -- Output raster file. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field='{}'\".format(field))\n        if use_z: args.append(\"--use_z\")\n        args.append(\"--output='{}'\".format(output))\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        return self.run_tool('block_minimum_gridding', args, callback) # returns 1 if error\n\n    def centroid(self, i, output, text_output=False, callback=None):\n        \"\"\"Calculates the centroid, or average location, of raster polygon objects.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        text_output -- Optional text output. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if text_output: args.append(\"--text_output\")\n        return self.run_tool('centroid', args, callback) # returns 1 if error\n\n    def centroid_vector(self, i, output, callback=None):\n        \"\"\"Identifies the centroid point of a vector polyline or polygon feature or a group of vector points.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('centroid_vector', args, callback) # returns 1 if error\n\n    def clump(self, i, output, diag=True, zero_back=False, callback=None):\n        \"\"\"Groups cells that form discrete areas, assigning them unique identifiers.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        diag -- Flag indicating whether diagonal connections should be considered. \n        zero_back -- Flag indicating whether zero values should be treated as a background. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if diag: args.append(\"--diag\")\n        if zero_back: args.append(\"--zero_back\")\n        return self.run_tool('clump', args, callback) # returns 1 if error\n\n    def construct_vector_tin(self, i, output, field=None, use_z=False, max_triangle_edge_length=None, callback=None):\n        \"\"\"Creates a vector triangular irregular network (TIN) for a set of vector points.\n\n        Keyword arguments:\n\n        i -- Input vector points file. \n        field -- Input field name in attribute table. \n        use_z -- Use the 'z' dimension of the Shapefile's geometry instead of an attribute field?. \n        output -- Output vector polygon file. \n        max_triangle_edge_length -- Optional maximum triangle edge length; triangles larger than this size will not be gridded. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if field is not None: args.append(\"--field='{}'\".format(field))\n        if use_z: args.append(\"--use_z\")\n        args.append(\"--output='{}'\".format(output))\n        if max_triangle_edge_length is not None: args.append(\"--max_triangle_edge_length='{}'\".format(max_triangle_edge_length))\n        return self.run_tool('construct_vector_tin', args, callback) # returns 1 if error\n\n    def create_hexagonal_vector_grid(self, i, output, width, orientation=\"horizontal\", callback=None):\n        \"\"\"Creates a hexagonal vector grid.\n\n        Keyword arguments:\n\n        i -- Input base file. \n        output -- Output vector polygon file. \n        width -- The grid cell width. \n        orientation -- Grid Orientation, 'horizontal' or 'vertical'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--width='{}'\".format(width))\n        args.append(\"--orientation={}\".format(orientation))\n        return self.run_tool('create_hexagonal_vector_grid', args, callback) # returns 1 if error\n\n    def create_plane(self, base, output, gradient=15.0, aspect=90.0, constant=0.0, callback=None):\n        \"\"\"Creates a raster image based on the equation for a simple plane.\n\n        Keyword arguments:\n\n        base -- Input base raster file. \n        output -- Output raster file. \n        gradient -- Slope gradient in degrees (-85.0 to 85.0). \n        aspect -- Aspect (direction) in degrees clockwise from north (0.0-360.0). \n        constant -- Constant value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--base='{}'\".format(base))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--gradient={}\".format(gradient))\n        args.append(\"--aspect={}\".format(aspect))\n        args.append(\"--constant={}\".format(constant))\n        return self.run_tool('create_plane', args, callback) # returns 1 if error\n\n    def create_rectangular_vector_grid(self, i, output, width, height, xorig=0, yorig=0, callback=None):\n        \"\"\"Creates a rectangular vector grid.\n\n        Keyword arguments:\n\n        i -- Input base file. \n        output -- Output vector polygon file. \n        width -- The grid cell width. \n        height -- The grid cell height. \n        xorig -- The grid origin x-coordinate. \n        yorig -- The grid origin y-coordinate. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--width='{}'\".format(width))\n        args.append(\"--height='{}'\".format(height))\n        args.append(\"--xorig={}\".format(xorig))\n        args.append(\"--yorig={}\".format(yorig))\n        return self.run_tool('create_rectangular_vector_grid', args, callback) # returns 1 if error\n\n    def dissolve(self, i, output, field=None, snap=0.0, callback=None):\n        \"\"\"Removes the interior, or shared, boundaries within a vector polygon coverage.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        field -- Dissolve field attribute (optional). \n        output -- Output vector file. \n        snap -- Snap tolerance. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if field is not None: args.append(\"--field='{}'\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--snap={}\".format(snap))\n        return self.run_tool('dissolve', args, callback) # returns 1 if error\n\n    def eliminate_coincident_points(self, i, output, tolerance, callback=None):\n        \"\"\"Removes any coincident, or nearly coincident, points from a vector points file.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output vector points file. \n        tolerance -- The distance tolerance for points. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--tolerance='{}'\".format(tolerance))\n        return self.run_tool('eliminate_coincident_points', args, callback) # returns 1 if error\n\n    def extend_vector_lines(self, i, output, dist, extend=\"both ends\", callback=None):\n        \"\"\"Extends vector lines by a specified distance.\n\n        Keyword arguments:\n\n        i -- Input vector polyline file. \n        output -- Output vector polyline file. \n        dist -- The distance to extend. \n        extend -- Extend direction, 'both ends' (default), 'line start', 'line end'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--dist='{}'\".format(dist))\n        args.append(\"--extend={}\".format(extend))\n        return self.run_tool('extend_vector_lines', args, callback) # returns 1 if error\n\n    def extract_nodes(self, i, output, callback=None):\n        \"\"\"Converts vector lines or polygons into vertex points.\n\n        Keyword arguments:\n\n        i -- Input vector lines or polygon file. \n        output -- Output vector points file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('extract_nodes', args, callback) # returns 1 if error\n\n    def extract_raster_values_at_points(self, inputs, points, out_text=False, callback=None):\n        \"\"\"Extracts the values of raster(s) at vector point locations.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        points -- Input vector points file. \n        out_text -- Output point values as text? Otherwise, the only output is to to the points file's attribute table. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--points='{}'\".format(points))\n        if out_text: args.append(\"--out_text\")\n        return self.run_tool('extract_raster_values_at_points', args, callback) # returns 1 if error\n\n    def filter_raster_features_by_area(self, i, output, threshold, background=\"zero\", callback=None):\n        \"\"\"Removes small-area features from a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        threshold -- Remove features with fewer grid cells than this threshold value. \n        background -- Background value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--threshold='{}'\".format(threshold))\n        args.append(\"--background={}\".format(background))\n        return self.run_tool('filter_raster_features_by_area', args, callback) # returns 1 if error\n\n    def find_lowest_or_highest_points(self, i, output, out_type=\"lowest\", callback=None):\n        \"\"\"Locates the lowest and/or highest valued cells in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output vector points file. \n        out_type -- Output type; one of 'area' (default) and 'volume'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--out_type={}\".format(out_type))\n        return self.run_tool('find_lowest_or_highest_points', args, callback) # returns 1 if error\n\n    def heat_map(self, i, output, weight_field=None, bandwidth=\"\", kernel=\"quartic\", cell_size=\"\", base=None, callback=None):\n        \"\"\"Calculates a heat map, or kernel density estimation (KDE), for an input point set.\n\n        Keyword arguments:\n\n        i -- Name of the input points shapefile. \n        weight_field -- Optional name of the attribute containing point weight. \n        output -- Name of the output raster image file. \n        bandwidth -- Bandwidth (metres). \n        kernel -- Kernel type; one of 'uniform', 'triangular', 'epanechnikov', 'quartic', 'triweight', 'tricube', 'gaussian', 'cosine', 'logistic', 'sigmoid', 'silverman'. \n        cell_size -- Optionally specified cell size of output raster, in metres. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if weight_field is not None: args.append(\"--weight_field='{}'\".format(weight_field))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--bandwidth={}\".format(bandwidth))\n        args.append(\"--kernel={}\".format(kernel))\n        args.append(\"--cell_size={}\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        return self.run_tool('heat_map', args, callback) # returns 1 if error\n\n    def idw_interpolation(self, i, field, output, use_z=False, weight=2.0, radius=None, min_points=None, cell_size=None, base=None, callback=None):\n        \"\"\"Interpolates vector points into a raster surface using an inverse-distance weighted scheme.\n\n        Keyword arguments:\n\n        i -- Input vector Points file. \n        field -- Input field name in attribute table. \n        use_z -- Use z-coordinate instead of field?. \n        output -- Output raster file. \n        weight -- IDW weight value. \n        radius -- Search Radius in map units. \n        min_points -- Minimum number of points. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field='{}'\".format(field))\n        if use_z: args.append(\"--use_z\")\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--weight={}\".format(weight))\n        if radius is not None: args.append(\"--radius='{}'\".format(radius))\n        if min_points is not None: args.append(\"--min_points='{}'\".format(min_points))\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        return self.run_tool('idw_interpolation', args, callback) # returns 1 if error\n\n    def layer_footprint(self, i, output, callback=None):\n        \"\"\"Creates a vector polygon footprint of the area covered by a raster grid or vector layer.\n\n        Keyword arguments:\n\n        i -- Input raster or vector file. \n        output -- Output vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('layer_footprint', args, callback) # returns 1 if error\n\n    def medoid(self, i, output, callback=None):\n        \"\"\"Calculates the medoid for a series of vector features contained in a shapefile.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('medoid', args, callback) # returns 1 if error\n\n    def minimum_bounding_box(self, i, output, criterion=\"area\", features=True, callback=None):\n        \"\"\"Creates a vector minimum bounding rectangle around vector features.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output vector polygon file. \n        criterion -- Minimization criterion; options include 'area' (default), 'length', 'width', and 'perimeter'. \n        features -- Find the minimum bounding rectangles around each individual vector feature. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--criterion={}\".format(criterion))\n        if features: args.append(\"--features\")\n        return self.run_tool('minimum_bounding_box', args, callback) # returns 1 if error\n\n    def minimum_bounding_circle(self, i, output, features=True, callback=None):\n        \"\"\"Delineates the minimum bounding circle (i.e. smallest enclosing circle) for a group of vectors.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output vector polygon file. \n        features -- Find the minimum bounding circle around each individual vector feature. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if features: args.append(\"--features\")\n        return self.run_tool('minimum_bounding_circle', args, callback) # returns 1 if error\n\n    def minimum_bounding_envelope(self, i, output, features=True, callback=None):\n        \"\"\"Creates a vector axis-aligned minimum bounding rectangle (envelope) around vector features.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output vector polygon file. \n        features -- Find the minimum bounding envelop around each individual vector feature. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if features: args.append(\"--features\")\n        return self.run_tool('minimum_bounding_envelope', args, callback) # returns 1 if error\n\n    def minimum_convex_hull(self, i, output, features=True, callback=None):\n        \"\"\"Creates a vector convex polygon around vector features.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output vector polygon file. \n        features -- Find the hulls around each vector feature. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if features: args.append(\"--features\")\n        return self.run_tool('minimum_convex_hull', args, callback) # returns 1 if error\n\n    def natural_neighbour_interpolation(self, i, output, field=None, use_z=False, cell_size=None, base=None, clip=True, callback=None):\n        \"\"\"Creates a raster grid based on Sibson's natural neighbour method.\n\n        Keyword arguments:\n\n        i -- Input vector points file. \n        field -- Input field name in attribute table. \n        use_z -- Use the 'z' dimension of the Shapefile's geometry instead of an attribute field?. \n        output -- Output raster file. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        clip -- Clip the data to the convex hull of the points?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if field is not None: args.append(\"--field='{}'\".format(field))\n        if use_z: args.append(\"--use_z\")\n        args.append(\"--output='{}'\".format(output))\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        if clip: args.append(\"--clip\")\n        return self.run_tool('natural_neighbour_interpolation', args, callback) # returns 1 if error\n\n    def nearest_neighbour_gridding(self, i, field, output, use_z=False, cell_size=None, base=None, max_dist=None, callback=None):\n        \"\"\"Creates a raster grid based on a set of vector points and assigns grid values using the nearest neighbour.\n\n        Keyword arguments:\n\n        i -- Input vector Points file. \n        field -- Input field name in attribute table. \n        use_z -- Use z-coordinate instead of field?. \n        output -- Output raster file. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        max_dist -- Maximum search distance (optional). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field='{}'\".format(field))\n        if use_z: args.append(\"--use_z\")\n        args.append(\"--output='{}'\".format(output))\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        if max_dist is not None: args.append(\"--max_dist='{}'\".format(max_dist))\n        return self.run_tool('nearest_neighbour_gridding', args, callback) # returns 1 if error\n\n    def polygon_area(self, i, callback=None):\n        \"\"\"Calculates the area of vector polygons.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('polygon_area', args, callback) # returns 1 if error\n\n    def polygon_long_axis(self, i, output, callback=None):\n        \"\"\"Used to map the long axis of polygon features.\n\n        Keyword arguments:\n\n        i -- Input vector polygons file. \n        output -- Output vector polyline file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('polygon_long_axis', args, callback) # returns 1 if error\n\n    def polygon_perimeter(self, i, callback=None):\n        \"\"\"Calculates the perimeter of vector polygons.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('polygon_perimeter', args, callback) # returns 1 if error\n\n    def polygon_short_axis(self, i, output, callback=None):\n        \"\"\"Used to map the short axis of polygon features.\n\n        Keyword arguments:\n\n        i -- Input vector polygons file. \n        output -- Output vector polyline file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('polygon_short_axis', args, callback) # returns 1 if error\n\n    def radial_basis_function_interpolation(self, i, field, output, use_z=False, radius=None, min_points=None, func_type=\"ThinPlateSpline\", poly_order=\"none\", weight=0.1, cell_size=None, base=None, callback=None):\n        \"\"\"Interpolates vector points into a raster surface using a radial basis function scheme.\n\n        Keyword arguments:\n\n        i -- Input vector points file. \n        field -- Input field name in attribute table. \n        use_z -- Use z-coordinate instead of field?. \n        output -- Output raster file. \n        radius -- Search Radius (in map units). \n        min_points -- Minimum number of points. \n        func_type -- Radial basis function type; options are 'ThinPlateSpline' (default), 'PolyHarmonic', 'Gaussian', 'MultiQuadric', 'InverseMultiQuadric'. \n        poly_order -- Polynomial order; options are 'none' (default), 'constant', 'affine'. \n        weight -- Weight parameter used in basis function. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field='{}'\".format(field))\n        if use_z: args.append(\"--use_z\")\n        args.append(\"--output='{}'\".format(output))\n        if radius is not None: args.append(\"--radius='{}'\".format(radius))\n        if min_points is not None: args.append(\"--min_points='{}'\".format(min_points))\n        args.append(\"--func_type={}\".format(func_type))\n        args.append(\"--poly_order={}\".format(poly_order))\n        args.append(\"--weight={}\".format(weight))\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        return self.run_tool('radial_basis_function_interpolation', args, callback) # returns 1 if error\n\n    def raster_area(self, i, output=None, out_text=False, units=\"grid cells\", zero_back=False, callback=None):\n        \"\"\"Calculates the area of polygons or classes within a raster image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        out_text -- Would you like to output polygon areas to text?. \n        units -- Area units; options include 'grid cells' and 'map units'. \n        zero_back -- Flag indicating whether zero values should be treated as a background. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        if out_text: args.append(\"--out_text\")\n        args.append(\"--units={}\".format(units))\n        if zero_back: args.append(\"--zero_back\")\n        return self.run_tool('raster_area', args, callback) # returns 1 if error\n\n    def raster_cell_assignment(self, i, output, assign=\"column\", callback=None):\n        \"\"\"Assign row or column number to cells.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        assign -- Which variable would you like to assign to grid cells? Options include 'column', 'row', 'x', and 'y'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--assign={}\".format(assign))\n        return self.run_tool('raster_cell_assignment', args, callback) # returns 1 if error\n\n    def raster_perimeter(self, i, output=None, out_text=False, units=\"grid cells\", zero_back=False, callback=None):\n        \"\"\"Calculates the perimeters of polygons or classes within a raster image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        out_text -- Would you like to output polygon areas to text?. \n        units -- Area units; options include 'grid cells' and 'map units'. \n        zero_back -- Flag indicating whether zero values should be treated as a background. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        if out_text: args.append(\"--out_text\")\n        args.append(\"--units={}\".format(units))\n        if zero_back: args.append(\"--zero_back\")\n        return self.run_tool('raster_perimeter', args, callback) # returns 1 if error\n\n    def reclass(self, i, output, reclass_vals, assign_mode=False, callback=None):\n        \"\"\"Reclassifies the values in a raster image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        reclass_vals -- Reclassification triplet values (new value; from value; to less than), e.g. '0.0;0.0;1.0;1.0;1.0;2.0'. \n        assign_mode -- Optional Boolean flag indicating whether to operate in assign mode, reclass_vals values are interpreted as new value; old value pairs. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--reclass_vals='{}'\".format(reclass_vals))\n        if assign_mode: args.append(\"--assign_mode\")\n        return self.run_tool('reclass', args, callback) # returns 1 if error\n\n    def reclass_equal_interval(self, i, output, interval=10.0, start_val=None, end_val=None, callback=None):\n        \"\"\"Reclassifies the values in a raster image based on equal-ranges.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        interval -- Class interval size. \n        start_val -- Optional starting value (default is input minimum value). \n        end_val -- Optional ending value (default is input maximum value). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--interval={}\".format(interval))\n        if start_val is not None: args.append(\"--start_val='{}'\".format(start_val))\n        if end_val is not None: args.append(\"--end_val='{}'\".format(end_val))\n        return self.run_tool('reclass_equal_interval', args, callback) # returns 1 if error\n\n    def reclass_from_file(self, i, reclass_file, output, callback=None):\n        \"\"\"Reclassifies the values in a raster image using reclass ranges in a text file.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        reclass_file -- Input text file containing reclass ranges. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--reclass_file='{}'\".format(reclass_file))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('reclass_from_file', args, callback) # returns 1 if error\n\n    def smooth_vectors(self, i, output, filter=3, callback=None):\n        \"\"\"Smooths a vector coverage of either a POLYLINE or POLYGON base ShapeType.\n\n        Keyword arguments:\n\n        i -- Input vector POLYLINE or POLYGON file. \n        output -- Output vector file. \n        filter -- The filter size, any odd integer greater than or equal to 3; default is 3. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        return self.run_tool('smooth_vectors', args, callback) # returns 1 if error\n\n    def split_vector_lines(self, i, output, length=None, callback=None):\n        \"\"\"Used to split a vector line coverage into even-lengthed segments.\n\n        Keyword arguments:\n\n        i -- Name of the input lines shapefile. \n        output -- Name of the output lines shapefile. \n        length -- Maximum segment length (m). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if length is not None: args.append(\"--length='{}'\".format(length))\n        return self.run_tool('split_vector_lines', args, callback) # returns 1 if error\n\n    def tin_gridding(self, i, output, field=None, use_z=False, resolution=None, base=None, max_triangle_edge_length=None, callback=None):\n        \"\"\"Creates a raster grid based on a triangular irregular network (TIN) fitted to vector points.\n\n        Keyword arguments:\n\n        i -- Input vector points file. \n        field -- Input field name in attribute table. \n        use_z -- Use the 'z' dimension of the Shapefile's geometry instead of an attribute field?. \n        output -- Output raster file. \n        resolution -- Output raster's grid resolution. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        max_triangle_edge_length -- Optional maximum triangle edge length; triangles larger than this size will not be gridded. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if field is not None: args.append(\"--field='{}'\".format(field))\n        if use_z: args.append(\"--use_z\")\n        args.append(\"--output='{}'\".format(output))\n        if resolution is not None: args.append(\"--resolution='{}'\".format(resolution))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        if max_triangle_edge_length is not None: args.append(\"--max_triangle_edge_length='{}'\".format(max_triangle_edge_length))\n        return self.run_tool('tin_gridding', args, callback) # returns 1 if error\n\n    def travelling_salesman_problem(self, i, output, duration=60, callback=None):\n        \"\"\"Finds approximate solutions to travelling salesman problems, the goal of which is to identify the shortest route connecting a set of locations.\n\n        Keyword arguments:\n\n        i -- Name of the input points shapefile. \n        output -- Name of the output lines shapefile. \n        duration -- Maximum duration, in seconds. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--duration={}\".format(duration))\n        return self.run_tool('travelling_salesman_problem', args, callback) # returns 1 if error\n\n    def vector_hex_binning(self, i, output, width, orientation=\"horizontal\", callback=None):\n        \"\"\"Hex-bins a set of vector points.\n\n        Keyword arguments:\n\n        i -- Input base file. \n        output -- Output vector polygon file. \n        width -- The grid cell width. \n        orientation -- Grid Orientation, 'horizontal' or 'vertical'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--width='{}'\".format(width))\n        args.append(\"--orientation={}\".format(orientation))\n        return self.run_tool('vector_hex_binning', args, callback) # returns 1 if error\n\n    def voronoi_diagram(self, i, output, callback=None):\n        \"\"\"Creates a vector Voronoi diagram for a set of vector points.\n\n        Keyword arguments:\n\n        i -- Input vector points file. \n        output -- Output vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('voronoi_diagram', args, callback) # returns 1 if error\n\n    ###############################\n    # GIS Analysis/Distance Tools #\n    ###############################\n\n    def buffer_raster(self, i, output, size, gridcells=False, callback=None):\n        \"\"\"Maps a distance-based buffer around each non-background (non-zero/non-nodata) grid cell in an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        size -- Buffer size. \n        gridcells -- Optional flag to indicate that the 'size' threshold should be measured in grid cells instead of the default map units. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--size='{}'\".format(size))\n        if gridcells: args.append(\"--gridcells\")\n        return self.run_tool('buffer_raster', args, callback) # returns 1 if error\n\n    def cost_allocation(self, source, backlink, output, callback=None):\n        \"\"\"Identifies the source cell to which each grid cell is connected by a least-cost pathway in a cost-distance analysis.\n\n        Keyword arguments:\n\n        source -- Input source raster file. \n        backlink -- Input backlink raster file generated by the cost-distance tool. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--source='{}'\".format(source))\n        args.append(\"--backlink='{}'\".format(backlink))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('cost_allocation', args, callback) # returns 1 if error\n\n    def cost_distance(self, source, cost, out_accum, out_backlink, callback=None):\n        \"\"\"Performs cost-distance accumulation on a cost surface and a group of source cells.\n\n        Keyword arguments:\n\n        source -- Input source raster file. \n        cost -- Input cost (friction) raster file. \n        out_accum -- Output cost accumulation raster file. \n        out_backlink -- Output backlink raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--source='{}'\".format(source))\n        args.append(\"--cost='{}'\".format(cost))\n        args.append(\"--out_accum='{}'\".format(out_accum))\n        args.append(\"--out_backlink='{}'\".format(out_backlink))\n        return self.run_tool('cost_distance', args, callback) # returns 1 if error\n\n    def cost_pathway(self, destination, backlink, output, zero_background=False, callback=None):\n        \"\"\"Performs cost-distance pathway analysis using a series of destination grid cells.\n\n        Keyword arguments:\n\n        destination -- Input destination raster file. \n        backlink -- Input backlink raster file generated by the cost-distance tool. \n        output -- Output cost pathway raster file. \n        zero_background -- Flag indicating whether zero values should be treated as a background. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--destination='{}'\".format(destination))\n        args.append(\"--backlink='{}'\".format(backlink))\n        args.append(\"--output='{}'\".format(output))\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('cost_pathway', args, callback) # returns 1 if error\n\n    def euclidean_allocation(self, i, output, callback=None):\n        \"\"\"Assigns grid cells in the output raster the value of the nearest target cell in the input image, measured by the Shih and Wu (2004) Euclidean distance transform.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('euclidean_allocation', args, callback) # returns 1 if error\n\n    def euclidean_distance(self, i, output, callback=None):\n        \"\"\"Calculates the Shih and Wu (2004) Euclidean distance transform.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('euclidean_distance', args, callback) # returns 1 if error\n\n    ##############################\n    # GIS Analysis/Overlay Tools #\n    ##############################\n\n    def average_overlay(self, inputs, output, callback=None):\n        \"\"\"Calculates the average for each grid cell from a group of raster images.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('average_overlay', args, callback) # returns 1 if error\n\n    def clip(self, i, clip, output, callback=None):\n        \"\"\"Extract all the features, or parts of features, that overlap with the features of the clip vector.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        clip -- Input clip polygon vector file. \n        output -- Output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--clip='{}'\".format(clip))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('clip', args, callback) # returns 1 if error\n\n    def clip_raster_to_polygon(self, i, polygons, output, maintain_dimensions=False, callback=None):\n        \"\"\"Clips a raster to a vector polygon.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        polygons -- Input vector polygons file. \n        output -- Output raster file. \n        maintain_dimensions -- Maintain input raster dimensions?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--polygons='{}'\".format(polygons))\n        args.append(\"--output='{}'\".format(output))\n        if maintain_dimensions: args.append(\"--maintain_dimensions\")\n        return self.run_tool('clip_raster_to_polygon', args, callback) # returns 1 if error\n\n    def count_if(self, inputs, output, value, callback=None):\n        \"\"\"Counts the number of occurrences of a specified value in a cell-stack of rasters.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        value -- Search value (e.g. countif value = 5.0). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--value='{}'\".format(value))\n        return self.run_tool('count_if', args, callback) # returns 1 if error\n\n    def difference(self, i, overlay, output, callback=None):\n        \"\"\"Outputs the features that occur in one of the two vector inputs but not both, i.e. no overlapping features.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        overlay -- Input overlay vector file. \n        output -- Output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--overlay='{}'\".format(overlay))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('difference', args, callback) # returns 1 if error\n\n    def erase(self, i, erase, output, callback=None):\n        \"\"\"Removes all the features, or parts of features, that overlap with the features of the erase vector polygon.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        erase -- Input erase polygon vector file. \n        output -- Output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--erase='{}'\".format(erase))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('erase', args, callback) # returns 1 if error\n\n    def erase_polygon_from_raster(self, i, polygons, output, callback=None):\n        \"\"\"Erases (cuts out) a vector polygon from a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        polygons -- Input vector polygons file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--polygons='{}'\".format(polygons))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('erase_polygon_from_raster', args, callback) # returns 1 if error\n\n    def highest_position(self, inputs, output, callback=None):\n        \"\"\"Identifies the stack position of the maximum value within a raster stack on a cell-by-cell basis.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('highest_position', args, callback) # returns 1 if error\n\n    def intersect(self, i, overlay, output, snap=0.0, callback=None):\n        \"\"\"Identifies the parts of features in common between two input vector layers.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        overlay -- Input overlay vector file. \n        output -- Output vector file. \n        snap -- Snap tolerance. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--overlay='{}'\".format(overlay))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--snap={}\".format(snap))\n        return self.run_tool('intersect', args, callback) # returns 1 if error\n\n    def line_intersections(self, input1, input2, output, callback=None):\n        \"\"\"Identifies points where the features of two vector line layers intersect.\n\n        Keyword arguments:\n\n        input1 -- Input vector polyline file. \n        input2 -- Input vector polyline file. \n        output -- Output vector point file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('line_intersections', args, callback) # returns 1 if error\n\n    def lowest_position(self, inputs, output, callback=None):\n        \"\"\"Identifies the stack position of the minimum value within a raster stack on a cell-by-cell basis.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('lowest_position', args, callback) # returns 1 if error\n\n    def max_absolute_overlay(self, inputs, output, callback=None):\n        \"\"\"Evaluates the maximum absolute value for each grid cell from a stack of input rasters.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('max_absolute_overlay', args, callback) # returns 1 if error\n\n    def max_overlay(self, inputs, output, callback=None):\n        \"\"\"Evaluates the maximum value for each grid cell from a stack of input rasters.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('max_overlay', args, callback) # returns 1 if error\n\n    def merge_line_segments(self, i, output, snap=0.0, callback=None):\n        \"\"\"Merges vector line segments into larger features.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output vector file. \n        snap -- Snap tolerance. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--snap={}\".format(snap))\n        return self.run_tool('merge_line_segments', args, callback) # returns 1 if error\n\n    def min_absolute_overlay(self, inputs, output, callback=None):\n        \"\"\"Evaluates the minimum absolute value for each grid cell from a stack of input rasters.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('min_absolute_overlay', args, callback) # returns 1 if error\n\n    def min_overlay(self, inputs, output, callback=None):\n        \"\"\"Evaluates the minimum value for each grid cell from a stack of input rasters.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('min_overlay', args, callback) # returns 1 if error\n\n    def multiply_overlay(self, inputs, output, callback=None):\n        \"\"\"Calculates the sum for each grid cell from a group of raster images.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('multiply_overlay', args, callback) # returns 1 if error\n\n    def percent_equal_to(self, inputs, comparison, output, callback=None):\n        \"\"\"Calculates the percentage of a raster stack that have cell values equal to an input on a cell-by-cell basis.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        comparison -- Input comparison raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--comparison='{}'\".format(comparison))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('percent_equal_to', args, callback) # returns 1 if error\n\n    def percent_greater_than(self, inputs, comparison, output, callback=None):\n        \"\"\"Calculates the percentage of a raster stack that have cell values greater than an input on a cell-by-cell basis.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        comparison -- Input comparison raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--comparison='{}'\".format(comparison))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('percent_greater_than', args, callback) # returns 1 if error\n\n    def percent_less_than(self, inputs, comparison, output, callback=None):\n        \"\"\"Calculates the percentage of a raster stack that have cell values less than an input on a cell-by-cell basis.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        comparison -- Input comparison raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--comparison='{}'\".format(comparison))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('percent_less_than', args, callback) # returns 1 if error\n\n    def pick_from_list(self, inputs, pos_input, output, callback=None):\n        \"\"\"Outputs the value from a raster stack specified by a position raster.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        pos_input -- Input position raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--pos_input='{}'\".format(pos_input))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('pick_from_list', args, callback) # returns 1 if error\n\n    def polygonize(self, inputs, output, callback=None):\n        \"\"\"Creates a polygon layer from two or more intersecting line features contained in one or more input vector line files.\n\n        Keyword arguments:\n\n        inputs -- Input vector polyline file. \n        output -- Output vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('polygonize', args, callback) # returns 1 if error\n\n    def split_with_lines(self, i, split, output, callback=None):\n        \"\"\"Splits the lines or polygons in one layer using the lines in another layer.\n\n        Keyword arguments:\n\n        i -- Input vector line or polygon file. \n        split -- Input vector polyline file. \n        output -- Output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--split='{}'\".format(split))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('split_with_lines', args, callback) # returns 1 if error\n\n    def sum_overlay(self, inputs, output, callback=None):\n        \"\"\"Calculates the sum for each grid cell from a group of raster images.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('sum_overlay', args, callback) # returns 1 if error\n\n    def symmetrical_difference(self, i, overlay, output, snap=0.0, callback=None):\n        \"\"\"Outputs the features that occur in one of the two vector inputs but not both, i.e. no overlapping features.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        overlay -- Input overlay vector file. \n        output -- Output vector file. \n        snap -- Snap tolerance. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--overlay='{}'\".format(overlay))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--snap={}\".format(snap))\n        return self.run_tool('symmetrical_difference', args, callback) # returns 1 if error\n\n    def union(self, i, overlay, output, snap=0.0, callback=None):\n        \"\"\"Splits vector layers at their overlaps, creating a layer containing all the portions from both input and overlay layers.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        overlay -- Input overlay vector file. \n        output -- Output vector file. \n        snap -- Snap tolerance. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--overlay='{}'\".format(overlay))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--snap={}\".format(snap))\n        return self.run_tool('union', args, callback) # returns 1 if error\n\n    def update_nodata_cells(self, input1, input2, output, callback=None):\n        \"\"\"Replaces the NoData values in an input raster with the corresponding values contained in a second update layer.\n\n        Keyword arguments:\n\n        input1 -- Input raster file 1. \n        input2 -- Input raster file 2; update layer. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('update_nodata_cells', args, callback) # returns 1 if error\n\n    def weighted_overlay(self, factors, weights, output, cost=None, constraints=None, scale_max=1.0, callback=None):\n        \"\"\"Performs a weighted sum on multiple input rasters after converting each image to a common scale. The tool performs a multi-criteria evaluation (MCE).\n\n        Keyword arguments:\n\n        factors -- Input factor raster files. \n        weights -- Weight values, contained in quotes and separated by commas or semicolons. Must have the same number as factors. \n        cost -- Boolean array indicating which factors are cost factors, contained in quotes and separated by commas or semicolons. Must have the same number as factors. \n        constraints -- Input constraints raster files. \n        output -- Output raster file. \n        scale_max -- Suitability scale maximum value (common values are 1.0, 100.0, and 255.0). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--factors='{}'\".format(factors))\n        args.append(\"--weights='{}'\".format(weights))\n        if cost is not None: args.append(\"--cost='{}'\".format(cost))\n        if constraints is not None: args.append(\"--constraints='{}'\".format(constraints))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--scale_max={}\".format(scale_max))\n        return self.run_tool('weighted_overlay', args, callback) # returns 1 if error\n\n    def weighted_sum(self, inputs, weights, output, callback=None):\n        \"\"\"Performs a weighted-sum overlay on multiple input raster images.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        weights -- Weight values, contained in quotes and separated by commas or semicolons. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--weights='{}'\".format(weights))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('weighted_sum', args, callback) # returns 1 if error\n\n    ##################################\n    # GIS Analysis/Patch Shape Tools #\n    ##################################\n\n    def boundary_shape_complexity(self, i, output, callback=None):\n        \"\"\"Calculates the complexity of the boundaries of raster polygons.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('boundary_shape_complexity', args, callback) # returns 1 if error\n\n    def compactness_ratio(self, i, callback=None):\n        \"\"\"Calculates the compactness ratio (A/P), a measure of shape complexity, for vector polygons.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('compactness_ratio', args, callback) # returns 1 if error\n\n    def edge_proportion(self, i, output, output_text=False, callback=None):\n        \"\"\"Calculate the proportion of cells in a raster polygon that are edge cells.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        output_text -- flag indicating whether a text report should also be output. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if output_text: args.append(\"--output_text\")\n        return self.run_tool('edge_proportion', args, callback) # returns 1 if error\n\n    def elongation_ratio(self, i, callback=None):\n        \"\"\"Calculates the elongation ratio for vector polygons.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('elongation_ratio', args, callback) # returns 1 if error\n\n    def find_patch_or_class_edge_cells(self, i, output, callback=None):\n        \"\"\"Finds all cells located on the edge of patch or class features.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('find_patch_or_class_edge_cells', args, callback) # returns 1 if error\n\n    def hole_proportion(self, i, callback=None):\n        \"\"\"Calculates the proportion of the total area of a polygon's holes relative to the area of the polygon's hull.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('hole_proportion', args, callback) # returns 1 if error\n\n    def linearity_index(self, i, callback=None):\n        \"\"\"Calculates the linearity index for vector polygons.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('linearity_index', args, callback) # returns 1 if error\n\n    def narrowness_index(self, i, output, callback=None):\n        \"\"\"Calculates the narrowness of raster polygons.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('narrowness_index', args, callback) # returns 1 if error\n\n    def patch_orientation(self, i, callback=None):\n        \"\"\"Calculates the orientation of vector polygons.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('patch_orientation', args, callback) # returns 1 if error\n\n    def perimeter_area_ratio(self, i, callback=None):\n        \"\"\"Calculates the perimeter-area ratio of vector polygons.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('perimeter_area_ratio', args, callback) # returns 1 if error\n\n    def radius_of_gyration(self, i, output, text_output=False, callback=None):\n        \"\"\"Calculates the distance of cells from their polygon's centroid.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        text_output -- Optional text output. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if text_output: args.append(\"--text_output\")\n        return self.run_tool('radius_of_gyration', args, callback) # returns 1 if error\n\n    def related_circumscribing_circle(self, i, callback=None):\n        \"\"\"Calculates the related circumscribing circle of vector polygons.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('related_circumscribing_circle', args, callback) # returns 1 if error\n\n    def shape_complexity_index(self, i, callback=None):\n        \"\"\"Calculates overall polygon shape complexity or irregularity.\n\n        Keyword arguments:\n\n        i -- Input vector polygon file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('shape_complexity_index', args, callback) # returns 1 if error\n\n    def shape_complexity_index_raster(self, i, output, callback=None):\n        \"\"\"Calculates the complexity of raster polygons or classes.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('shape_complexity_index_raster', args, callback) # returns 1 if error\n\n    ############################\n    # Geomorphometric Analysis #\n    ############################\n\n    def accumulation_curvature(self, dem, output, log=False, zfactor=1.0, callback=None):\n        \"\"\"This tool calculates accumulation curvature from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Name of the input raster DEM file. \n        output -- Name of the output raster image file. \n        log -- Display output values using a log-scale. \n        zfactor -- Z conversion factor. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('accumulation_curvature', args, callback) # returns 1 if error\n\n    def aspect(self, dem, output, zfactor=None, callback=None):\n        \"\"\"Calculates an aspect raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if zfactor is not None: args.append(\"--zfactor='{}'\".format(zfactor))\n        return self.run_tool('aspect', args, callback) # returns 1 if error\n\n    def assess_route(self, routes, dem, output, length=\"\", dist=20, callback=None):\n        \"\"\"This tool assesses a route for slope, elevation, and visibility variation.\n\n        Keyword arguments:\n\n        routes -- Name of the input routes vector file. \n        dem -- Name of the input DEM raster file. \n        output -- Name of the output lines shapefile. \n        length -- Maximum segment length (m). \n        dist -- Search distance, in grid cells, used in visibility analysis. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--routes='{}'\".format(routes))\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--length={}\".format(length))\n        args.append(\"--dist={}\".format(dist))\n        return self.run_tool('assess_route', args, callback) # returns 1 if error\n\n    def average_normal_vector_angular_deviation(self, dem, output, filter=11, callback=None):\n        \"\"\"Calculates the circular variance of aspect at a scale for a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filter -- Size of the filter kernel. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        return self.run_tool('average_normal_vector_angular_deviation', args, callback) # returns 1 if error\n\n    def breakline_mapping(self, dem, output, threshold=2.0, min_length=3, callback=None):\n        \"\"\"This tool maps breaklines from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Name of the input raster image file. \n        output -- Name of the output vector lines file. \n        threshold -- Threshold value (0 - infinity but typcially 1 to 5 works well). \n        min_length -- Minimum line length, in grid cells. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--threshold={}\".format(threshold))\n        args.append(\"--min_length={}\".format(min_length))\n        return self.run_tool('breakline_mapping', args, callback) # returns 1 if error\n\n    def circular_variance_of_aspect(self, dem, output, filter=11, callback=None):\n        \"\"\"Calculates the circular variance of aspect at a scale for a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filter -- Size of the filter kernel. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        return self.run_tool('circular_variance_of_aspect', args, callback) # returns 1 if error\n\n    def contours_from_points(self, i, output, field=None, use_z=False, max_triangle_edge_length=None, interval=10.0, base=0.0, smooth=5, callback=None):\n        \"\"\"Creates a contour coverage from a set of input points.\n\n        Keyword arguments:\n\n        i -- Input vector points file. \n        field -- Input field name in attribute table. \n        use_z -- Use the 'z' dimension of the Shapefile's geometry instead of an attribute field?. \n        output -- Output vector lines file. \n        max_triangle_edge_length -- Optional maximum triangle edge length; triangles larger than this size will not be gridded. \n        interval -- Contour interval. \n        base -- Base contour height. \n        smooth -- Smoothing filter size (in num. points), e.g. 3, 5, 7, 9, 11. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if field is not None: args.append(\"--field='{}'\".format(field))\n        if use_z: args.append(\"--use_z\")\n        args.append(\"--output='{}'\".format(output))\n        if max_triangle_edge_length is not None: args.append(\"--max_triangle_edge_length='{}'\".format(max_triangle_edge_length))\n        args.append(\"--interval={}\".format(interval))\n        args.append(\"--base={}\".format(base))\n        args.append(\"--smooth={}\".format(smooth))\n        return self.run_tool('contours_from_points', args, callback) # returns 1 if error\n\n    def contours_from_raster(self, i, output, interval=10.0, base=0.0, smooth=9, tolerance=10.0, callback=None):\n        \"\"\"Derives a vector contour coverage from a raster surface.\n\n        Keyword arguments:\n\n        i -- Input surface raster file. \n        output -- Output vector contour file. \n        interval -- Contour interval. \n        base -- Base contour height. \n        smooth -- Smoothing filter size (in num. points), e.g. 3, 5, 7, 9, 11. \n        tolerance -- Tolerance factor, in degrees (0-45); determines generalization level. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--interval={}\".format(interval))\n        args.append(\"--base={}\".format(base))\n        args.append(\"--smooth={}\".format(smooth))\n        args.append(\"--tolerance={}\".format(tolerance))\n        return self.run_tool('contours_from_raster', args, callback) # returns 1 if error\n\n    def curvedness(self, dem, output, log=False, zfactor=1.0, callback=None):\n        \"\"\"This tool calculates curvedness from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Name of the input raster DEM file. \n        output -- Name of the output raster image file. \n        log -- Display output values using a log-scale. \n        zfactor -- Z conversion factor. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('curvedness', args, callback) # returns 1 if error\n\n    def dem_void_filling(self, dem, fill, output, mean_plane_dist=20, edge_treatment=\"use DEM\", weight_value=2.0, callback=None):\n        \"\"\"This tool can be used to fill the void areas of a DEM using another fill DEM data set.\n\n        Keyword arguments:\n\n        dem -- Name of the input raster DEM file, containing the void areas. \n        fill -- Name of the input fill DEM file, containing the values used to fill the void areas in the other DEM. \n        output -- Name of the output void-filled DEM file. \n        mean_plane_dist -- Distance to void edge at which the mean-plane value is used as an offset, measured in grid cells. \n        edge_treatment -- How should void-edge cells be treated? Options include 'use DEM' (default), 'use Fill', 'average'. \n        weight_value -- Weight value used for IDW interpolation (default is 2.0). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--fill='{}'\".format(fill))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--mean_plane_dist={}\".format(mean_plane_dist))\n        args.append(\"--edge_treatment={}\".format(edge_treatment))\n        args.append(\"--weight_value={}\".format(weight_value))\n        return self.run_tool('dem_void_filling', args, callback) # returns 1 if error\n\n    def dev_from_mean_elev(self, dem, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Calculates deviation from mean elevation.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('dev_from_mean_elev', args, callback) # returns 1 if error\n\n    def diff_from_mean_elev(self, dem, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Calculates difference from mean elevation (equivalent to a high-pass filter).\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('diff_from_mean_elev', args, callback) # returns 1 if error\n\n    def difference_curvature(self, dem, output, log=False, zfactor=1.0, callback=None):\n        \"\"\"This tool calculates difference curvature from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Name of the input raster DEM file. \n        output -- Name of the output raster image file. \n        log -- Display output values using a log-scale. \n        zfactor -- Z conversion factor. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('difference_curvature', args, callback) # returns 1 if error\n\n    def directional_relief(self, dem, output, azimuth=0.0, max_dist=None, callback=None):\n        \"\"\"Calculates relief for cells in an input DEM for a specified direction.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        azimuth -- Wind azimuth in degrees. \n        max_dist -- Optional maximum search distance (unspecified if none; in xy units). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--azimuth={}\".format(azimuth))\n        if max_dist is not None: args.append(\"--max_dist='{}'\".format(max_dist))\n        return self.run_tool('directional_relief', args, callback) # returns 1 if error\n\n    def downslope_index(self, dem, output, drop=2.0, out_type=\"tangent\", callback=None):\n        \"\"\"Calculates the Hjerdt et al. (2004) downslope index.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        drop -- Vertical drop value (default is 2.0). \n        out_type -- Output type, options include 'tangent', 'degrees', 'radians', 'distance' (default is 'tangent'). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--drop={}\".format(drop))\n        args.append(\"--out_type={}\".format(out_type))\n        return self.run_tool('downslope_index', args, callback) # returns 1 if error\n\n    def edge_density(self, dem, output, filter=11, norm_diff=5.0, zfactor=None, callback=None):\n        \"\"\"Calculates the density of edges, or breaks-in-slope within DEMs.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filter -- Size of the filter kernel. \n        norm_diff -- Maximum difference in normal vectors, in degrees. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        args.append(\"--norm_diff={}\".format(norm_diff))\n        if zfactor is not None: args.append(\"--zfactor='{}'\".format(zfactor))\n        return self.run_tool('edge_density', args, callback) # returns 1 if error\n\n    def elev_above_pit(self, dem, output, callback=None):\n        \"\"\"Calculate the elevation of each grid cell above the nearest downstream pit cell or grid edge cell.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('elev_above_pit', args, callback) # returns 1 if error\n\n    def elev_percentile(self, dem, output, filterx=11, filtery=11, sig_digits=2, callback=None):\n        \"\"\"Calculates the elevation percentile raster from a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        sig_digits -- Number of significant digits. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        args.append(\"--sig_digits={}\".format(sig_digits))\n        return self.run_tool('elev_percentile', args, callback) # returns 1 if error\n\n    def elev_relative_to_min_max(self, dem, output, callback=None):\n        \"\"\"Calculates the elevation of a location relative to the minimum and maximum elevations in a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('elev_relative_to_min_max', args, callback) # returns 1 if error\n\n    def elev_relative_to_watershed_min_max(self, dem, watersheds, output, callback=None):\n        \"\"\"Calculates the elevation of a location relative to the minimum and maximum elevations in a watershed.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        watersheds -- Input raster watersheds file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--watersheds='{}'\".format(watersheds))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('elev_relative_to_watershed_min_max', args, callback) # returns 1 if error\n\n    def embankment_mapping(self, dem, road_vec, output, search_dist=2.5, min_road_width=6.0, typical_width=30.0, max_height=2.0, max_width=60.0, max_increment=0.05, spillout_slope=4.0, remove_embankments=False, callback=None):\n        \"\"\"Maps and/or removes road embankments from an input fine-resolution DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        road_vec -- Input vector polygons file. \n        output -- Output raster file. \n        search_dist -- Search distance used to reposition transportation vectors onto road embankments (in map units). \n        min_road_width -- Minimum road width; this is the width of the paved road surface (in map units). \n        typical_width -- Typical embankment width; this is the maximum width of an embankment with roadside ditches (in map units). \n        max_height -- Typical embankment maximum height; this is the height a typical embankment with roadside ditches (in map units). \n        max_width -- Maximum embankment width, typically where embankments traverse steep-sided valleys (in map units). \n        max_increment -- Maximum upwards increment between neighbouring cells on an embankment (in elevation units). \n        spillout_slope -- Spillout slope (in degrees). \n        remove_embankments -- Optional flag indicating whether to output a DEM with embankments removed (true) or an embankment raster map (false). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--road_vec='{}'\".format(road_vec))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--search_dist={}\".format(search_dist))\n        args.append(\"--min_road_width={}\".format(min_road_width))\n        args.append(\"--typical_width={}\".format(typical_width))\n        args.append(\"--max_height={}\".format(max_height))\n        args.append(\"--max_width={}\".format(max_width))\n        args.append(\"--max_increment={}\".format(max_increment))\n        args.append(\"--spillout_slope={}\".format(spillout_slope))\n        if remove_embankments: args.append(\"--remove_embankments\")\n        return self.run_tool('embankment_mapping', args, callback) # returns 1 if error\n\n    def exposure_towards_wind_flux(self, dem, output, azimuth=\"\", max_dist=\"\", zfactor=\"\", callback=None):\n        \"\"\"Evaluates hydrologic connectivity within a DEM.\n\n        Keyword arguments:\n\n        dem -- Name of the input DEM raster file. \n        output -- Name of the output raster file. \n        azimuth -- Wind azimuth, in degrees. \n        max_dist -- Optional maximum search distance. Minimum value is 5 x cell size. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--azimuth={}\".format(azimuth))\n        args.append(\"--max_dist={}\".format(max_dist))\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('exposure_towards_wind_flux', args, callback) # returns 1 if error\n\n    def feature_preserving_smoothing(self, dem, output, filter=11, norm_diff=15.0, num_iter=3, max_diff=0.5, zfactor=None, callback=None):\n        \"\"\"Reduces short-scale variation in an input DEM using a modified Sun et al. (2007) algorithm.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filter -- Size of the filter kernel. \n        norm_diff -- Maximum difference in normal vectors, in degrees. \n        num_iter -- Number of iterations. \n        max_diff -- Maximum allowable absolute elevation change (optional). \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        args.append(\"--norm_diff={}\".format(norm_diff))\n        args.append(\"--num_iter={}\".format(num_iter))\n        args.append(\"--max_diff={}\".format(max_diff))\n        if zfactor is not None: args.append(\"--zfactor='{}'\".format(zfactor))\n        return self.run_tool('feature_preserving_smoothing', args, callback) # returns 1 if error\n\n    def fetch_analysis(self, dem, output, azimuth=0.0, hgt_inc=0.05, callback=None):\n        \"\"\"Performs an analysis of fetch or upwind distance to an obstacle.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        azimuth -- Wind azimuth in degrees in degrees. \n        hgt_inc -- Height increment value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--azimuth={}\".format(azimuth))\n        args.append(\"--hgt_inc={}\".format(hgt_inc))\n        return self.run_tool('fetch_analysis', args, callback) # returns 1 if error\n\n    def fill_missing_data(self, i, output, filter=11, weight=2.0, no_edges=True, callback=None):\n        \"\"\"Fills NoData holes in a DEM.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filter -- Filter size (cells). \n        weight -- IDW weight value. \n        no_edges -- Optional flag indicating whether to exclude NoData cells in edge regions. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        args.append(\"--weight={}\".format(weight))\n        if no_edges: args.append(\"--no_edges\")\n        return self.run_tool('fill_missing_data', args, callback) # returns 1 if error\n\n    def find_ridges(self, dem, output, line_thin=True, callback=None):\n        \"\"\"Identifies potential ridge and peak grid cells.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        line_thin -- Optional flag indicating whether post-processing line-thinning should be performed. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if line_thin: args.append(\"--line_thin\")\n        return self.run_tool('find_ridges', args, callback) # returns 1 if error\n\n    def gaussian_curvature(self, dem, output, log=False, zfactor=None, callback=None):\n        \"\"\"Calculates a mean curvature raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        log -- Display output values using a log-scale. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        if zfactor is not None: args.append(\"--zfactor='{}'\".format(zfactor))\n        return self.run_tool('gaussian_curvature', args, callback) # returns 1 if error\n\n    def gaussian_scale_space(self, dem, output, output_zscore, output_scale, points=None, sigma=0.5, step=0.5, num_steps=10, lsp=\"Slope\", z_factor=None, callback=None):\n        \"\"\"Uses the fast Gaussian approximation algorithm to produce scaled land-surface parameter measurements from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Name of the input DEM raster file. \n        points -- Name of the input vector points shapefile. \n        output -- Name of the output land-surface parameter raster file. \n        output_zscore -- Name of the output z-score raster file. \n        output_scale -- Name of the output scale raster file. \n        sigma -- Initial sigma value (cells). \n        step -- Step size as any positive non-zero integer. \n        num_steps -- Number of steps. \n        lsp -- Output land-surface parameter; one of 'AnisotropyLTP', 'Aspect', 'DiffMeanElev', 'Eastness', 'Elevation', 'Hillshade', 'MeanCurvature', 'Northness', 'PlanCurvature', 'ProfileCurvature', 'Ruggedness', 'Slope', 'TanCurvature', 'TotalCurvature'. \n        z_factor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        if points is not None: args.append(\"--points='{}'\".format(points))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--output_zscore='{}'\".format(output_zscore))\n        args.append(\"--output_scale='{}'\".format(output_scale))\n        args.append(\"--sigma={}\".format(sigma))\n        args.append(\"--step={}\".format(step))\n        args.append(\"--num_steps={}\".format(num_steps))\n        args.append(\"--lsp={}\".format(lsp))\n        if z_factor is not None: args.append(\"--z_factor='{}'\".format(z_factor))\n        return self.run_tool('gaussian_scale_space', args, callback) # returns 1 if error\n\n    def generating_function(self, dem, output, log=False, zfactor=1.0, callback=None):\n        \"\"\"This tool calculates generating function from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Name of the input raster DEM file. \n        output -- Name of the output raster image file. \n        log -- Display output values using a log-scale. \n        zfactor -- Z conversion factor. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('generating_function', args, callback) # returns 1 if error\n\n    def geomorphons(self, dem, output, search=50, threshold=0.0, fdist=0, skip=0, forms=True, residuals=False, callback=None):\n        \"\"\"Computes geomorphon patterns.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        search -- Look up distance (in cells). \n        threshold -- Flatness threshold for the classification function (in degrees). \n        fdist -- Distance (in cells) to begin reducing the flatness threshold to avoid problems with pseudo-flat lines-of-sight. \n        skip -- Distance (in cells) to begin calculating lines-of-sight. \n        forms -- Classify geomorphons into 10 common land morphologies, else output ternary pattern. \n        residuals -- Convert elevation to residuals of a linear model. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--search={}\".format(search))\n        args.append(\"--threshold={}\".format(threshold))\n        args.append(\"--fdist={}\".format(fdist))\n        args.append(\"--skip={}\".format(skip))\n        if forms: args.append(\"--forms\")\n        if residuals: args.append(\"--residuals\")\n        return self.run_tool('geomorphons', args, callback) # returns 1 if error\n\n    def hillshade(self, dem, output, azimuth=315.0, altitude=30.0, zfactor=None, callback=None):\n        \"\"\"Calculates a hillshade raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        azimuth -- Illumination source azimuth in degrees. \n        altitude -- Illumination source altitude in degrees. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--azimuth={}\".format(azimuth))\n        args.append(\"--altitude={}\".format(altitude))\n        if zfactor is not None: args.append(\"--zfactor='{}'\".format(zfactor))\n        return self.run_tool('hillshade', args, callback) # returns 1 if error\n\n    def horizon_angle(self, dem, output, azimuth=0.0, max_dist=100.0, callback=None):\n        \"\"\"Calculates horizon angle (maximum upwind slope) for each grid cell in an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        azimuth -- Azimuth, in degrees. \n        max_dist -- Optional maximum search distance (unspecified if none; in xy units). Minimum value is 5 x cell size. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--azimuth={}\".format(azimuth))\n        args.append(\"--max_dist={}\".format(max_dist))\n        return self.run_tool('horizon_angle', args, callback) # returns 1 if error\n\n    def horizontal_excess_curvature(self, dem, output, log=False, zfactor=1.0, callback=None):\n        \"\"\"This tool calculates horizontal excess curvature from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Name of the input raster DEM file. \n        output -- Name of the output raster image file. \n        log -- Display output values using a log-scale. \n        zfactor -- Z conversion factor. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('horizontal_excess_curvature', args, callback) # returns 1 if error\n\n    def hypsometric_analysis(self, inputs, output, watershed=None, callback=None):\n        \"\"\"Calculates a hypsometric curve for one or more DEMs.\n\n        Keyword arguments:\n\n        inputs -- Input DEM files. \n        watershed -- Input watershed files (optional). \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        if watershed is not None: args.append(\"--watershed='{}'\".format(watershed))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('hypsometric_analysis', args, callback) # returns 1 if error\n\n    def hypsometrically_tinted_hillshade(self, dem, output, altitude=45.0, hs_weight=0.5, brightness=0.5, atmospheric=0.0, palette=\"atlas\", reverse=False, zfactor=None, full_mode=False, callback=None):\n        \"\"\"Creates an colour shaded relief image from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        altitude -- Illumination source altitude in degrees. \n        hs_weight -- Weight given to hillshade relative to relief (0.0-1.0). \n        brightness -- Brightness factor (0.0-1.0). \n        atmospheric -- Atmospheric effects weight (0.0-1.0). \n        palette -- Options include 'atlas', 'high_relief', 'arid', 'soft', 'muted', 'purple', 'viridis', 'gn_yl', 'pi_y_g', 'bl_yl_rd', and 'deep'. \n        reverse -- Optional flag indicating whether to use reverse the palette. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        full_mode -- Optional flag indicating whether to use full 360-degrees of illumination sources. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--altitude={}\".format(altitude))\n        args.append(\"--hs_weight={}\".format(hs_weight))\n        args.append(\"--brightness={}\".format(brightness))\n        args.append(\"--atmospheric={}\".format(atmospheric))\n        args.append(\"--palette={}\".format(palette))\n        if reverse: args.append(\"--reverse\")\n        if zfactor is not None: args.append(\"--zfactor='{}'\".format(zfactor))\n        if full_mode: args.append(\"--full_mode\")\n        return self.run_tool('hypsometrically_tinted_hillshade', args, callback) # returns 1 if error\n\n    def local_hypsometric_analysis(self, i, out_mag, out_scale, min_scale=4, step=1, num_steps=10, step_nonlinearity=1.0, callback=None):\n        \"\"\"This tool calculates a local, neighbourhood-based hypsometric integral raster.\n\n        Keyword arguments:\n\n        i -- Name of the input raster DEM file. \n        out_mag -- Name of the openness output raster file. \n        out_scale -- Name of the openness output raster file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        num_steps -- Number of steps. \n        step_nonlinearity -- Step nonlinearity factor (1.0-2.0 is typical). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--out_mag='{}'\".format(out_mag))\n        args.append(\"--out_scale='{}'\".format(out_scale))\n        args.append(\"--min_scale={}\".format(min_scale))\n        args.append(\"--step={}\".format(step))\n        args.append(\"--num_steps={}\".format(num_steps))\n        args.append(\"--step_nonlinearity={}\".format(step_nonlinearity))\n        return self.run_tool('local_hypsometric_analysis', args, callback) # returns 1 if error\n\n    def local_quadratic_regression(self, dem, output, filter=3, callback=None):\n        \"\"\"An implementation of the constrained quadratic regression algorithm using a flexible window size described in Wood (1996).\n\n        Keyword arguments:\n\n        dem -- Name of the input DEM raster file. \n        output -- Name of the output raster file. \n        filter -- Edge length of the filter kernel. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        return self.run_tool('local_quadratic_regression', args, callback) # returns 1 if error\n\n    def map_off_terrain_objects(self, dem, output, max_slope=40.0, min_size=1, callback=None):\n        \"\"\"Maps off-terrain objects in a digital elevation model (DEM).\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        max_slope -- Maximum inter-cell absolute slope. \n        min_size -- Minimum feature size, in grid cells. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--max_slope={}\".format(max_slope))\n        args.append(\"--min_size={}\".format(min_size))\n        return self.run_tool('map_off_terrain_objects', args, callback) # returns 1 if error\n\n    def max_anisotropy_dev(self, dem, out_mag, out_scale, max_scale, min_scale=3, step=2, callback=None):\n        \"\"\"Calculates the maximum anisotropy (directionality) in elevation deviation over a range of spatial scales.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        out_mag -- Output raster DEVmax magnitude file. \n        out_scale -- Output raster DEVmax scale file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        max_scale -- Maximum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--out_mag='{}'\".format(out_mag))\n        args.append(\"--out_scale='{}'\".format(out_scale))\n        args.append(\"--min_scale={}\".format(min_scale))\n        args.append(\"--max_scale='{}'\".format(max_scale))\n        args.append(\"--step={}\".format(step))\n        return self.run_tool('max_anisotropy_dev', args, callback) # returns 1 if error\n\n    def max_anisotropy_dev_signature(self, dem, points, output, max_scale, min_scale=1, step=1, callback=None):\n        \"\"\"Calculates the anisotropy in deviation from mean for points over a range of spatial scales.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        points -- Input vector points file. \n        output -- Output HTML file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        max_scale -- Maximum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--points='{}'\".format(points))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--min_scale={}\".format(min_scale))\n        args.append(\"--max_scale='{}'\".format(max_scale))\n        args.append(\"--step={}\".format(step))\n        return self.run_tool('max_anisotropy_dev_signature', args, callback) # returns 1 if error\n\n    def max_branch_length(self, dem, output, log=False, callback=None):\n        \"\"\"Lindsay and Seibert's (2013) branch length index is used to map drainage divides or ridge lines.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        log -- Optional flag to request the output be log-transformed. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        return self.run_tool('max_branch_length', args, callback) # returns 1 if error\n\n    def max_difference_from_mean(self, dem, out_mag, out_scale, min_scale, max_scale, step=1, callback=None):\n        \"\"\"Calculates the maximum difference from mean elevation over a range of spatial scales.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        out_mag -- Output raster DIFFmax magnitude file. \n        out_scale -- Output raster DIFFmax scale file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        max_scale -- Maximum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--out_mag='{}'\".format(out_mag))\n        args.append(\"--out_scale='{}'\".format(out_scale))\n        args.append(\"--min_scale='{}'\".format(min_scale))\n        args.append(\"--max_scale='{}'\".format(max_scale))\n        args.append(\"--step={}\".format(step))\n        return self.run_tool('max_difference_from_mean', args, callback) # returns 1 if error\n\n    def max_downslope_elev_change(self, dem, output, callback=None):\n        \"\"\"Calculates the maximum downslope change in elevation between a grid cell and its eight downslope neighbors.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('max_downslope_elev_change', args, callback) # returns 1 if error\n\n    def max_elev_dev_signature(self, dem, points, output, min_scale, max_scale, step=10, callback=None):\n        \"\"\"Calculates the maximum elevation deviation over a range of spatial scales and for a set of points.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        points -- Input vector points file. \n        output -- Output HTML file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        max_scale -- Maximum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--points='{}'\".format(points))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--min_scale='{}'\".format(min_scale))\n        args.append(\"--max_scale='{}'\".format(max_scale))\n        args.append(\"--step={}\".format(step))\n        return self.run_tool('max_elev_dev_signature', args, callback) # returns 1 if error\n\n    def max_elevation_deviation(self, dem, out_mag, out_scale, min_scale, max_scale, step=1, callback=None):\n        \"\"\"Calculates the maximum elevation deviation over a range of spatial scales.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        out_mag -- Output raster DEVmax magnitude file. \n        out_scale -- Output raster DEVmax scale file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        max_scale -- Maximum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--out_mag='{}'\".format(out_mag))\n        args.append(\"--out_scale='{}'\".format(out_scale))\n        args.append(\"--min_scale='{}'\".format(min_scale))\n        args.append(\"--max_scale='{}'\".format(max_scale))\n        args.append(\"--step={}\".format(step))\n        return self.run_tool('max_elevation_deviation', args, callback) # returns 1 if error\n\n    def max_upslope_elev_change(self, dem, output, callback=None):\n        \"\"\"Calculates the maximum upslope change in elevation between a grid cell and its eight downslope neighbors.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('max_upslope_elev_change', args, callback) # returns 1 if error\n\n    def maximal_curvature(self, dem, output, log=False, zfactor=None, callback=None):\n        \"\"\"Calculates a mean curvature raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        log -- Display output values using a log-scale. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        if zfactor is not None: args.append(\"--zfactor='{}'\".format(zfactor))\n        return self.run_tool('maximal_curvature', args, callback) # returns 1 if error\n\n    def mean_curvature(self, dem, output, log=False, zfactor=None, callback=None):\n        \"\"\"Calculates a mean curvature raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        log -- Display output values using a log-scale. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        if zfactor is not None: args.append(\"--zfactor='{}'\".format(zfactor))\n        return self.run_tool('mean_curvature', args, callback) # returns 1 if error\n\n    def min_downslope_elev_change(self, dem, output, callback=None):\n        \"\"\"Calculates the minimum downslope change in elevation between a grid cell and its eight downslope neighbors.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('min_downslope_elev_change', args, callback) # returns 1 if error\n\n    def minimal_curvature(self, dem, output, log=False, zfactor=None, callback=None):\n        \"\"\"Calculates a mean curvature raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        log -- Display output values using a log-scale. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        if zfactor is not None: args.append(\"--zfactor='{}'\".format(zfactor))\n        return self.run_tool('minimal_curvature', args, callback) # returns 1 if error\n\n    def multidirectional_hillshade(self, dem, output, altitude=45.0, zfactor=None, full_mode=False, callback=None):\n        \"\"\"Calculates a multi-direction hillshade raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        altitude -- Illumination source altitude in degrees. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        full_mode -- Optional flag indicating whether to use full 360-degrees of illumination sources. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--altitude={}\".format(altitude))\n        if zfactor is not None: args.append(\"--zfactor='{}'\".format(zfactor))\n        if full_mode: args.append(\"--full_mode\")\n        return self.run_tool('multidirectional_hillshade', args, callback) # returns 1 if error\n\n    def multiscale_curvatures(self, dem, out_mag, curv_type=\"ProfileCurv\", out_scale=None, min_scale=0, step=1, num_steps=1, step_nonlinearity=1.0, log=True, standardize=False, callback=None):\n        \"\"\"This tool calculates several multiscale curvatures and curvature-based indices from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Name of the input raster DEM file. \n        curv_type -- Curvature type. \n        out_mag -- Output raster magnitude file. \n        out_scale -- Output raster scale file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        num_steps -- Number of steps. \n        step_nonlinearity -- Step nonlinearity factor (1.0-2.0 is typical). \n        log -- Display output values using a log-scale. \n        standardize -- Should each scale be standardized to z-scores?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--curv_type={}\".format(curv_type))\n        args.append(\"--out_mag='{}'\".format(out_mag))\n        if out_scale is not None: args.append(\"--out_scale='{}'\".format(out_scale))\n        args.append(\"--min_scale={}\".format(min_scale))\n        args.append(\"--step={}\".format(step))\n        args.append(\"--num_steps={}\".format(num_steps))\n        args.append(\"--step_nonlinearity={}\".format(step_nonlinearity))\n        if log: args.append(\"--log\")\n        if standardize: args.append(\"--standardize\")\n        return self.run_tool('multiscale_curvatures', args, callback) # returns 1 if error\n\n    def multiscale_elevation_percentile(self, dem, out_mag, out_scale, sig_digits=3, min_scale=4, step=1, num_steps=10, step_nonlinearity=1.0, callback=None):\n        \"\"\"Calculates surface roughness over a range of spatial scales.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        out_mag -- Output raster roughness magnitude file. \n        out_scale -- Output raster roughness scale file. \n        sig_digits -- Number of significant digits. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        num_steps -- Number of steps. \n        step_nonlinearity -- Step nonlinearity factor (1.0-2.0 is typical). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--out_mag='{}'\".format(out_mag))\n        args.append(\"--out_scale='{}'\".format(out_scale))\n        args.append(\"--sig_digits={}\".format(sig_digits))\n        args.append(\"--min_scale={}\".format(min_scale))\n        args.append(\"--step={}\".format(step))\n        args.append(\"--num_steps={}\".format(num_steps))\n        args.append(\"--step_nonlinearity={}\".format(step_nonlinearity))\n        return self.run_tool('multiscale_elevation_percentile', args, callback) # returns 1 if error\n\n    def multiscale_roughness(self, dem, out_mag, out_scale, max_scale, min_scale=1, step=1, callback=None):\n        \"\"\"Calculates surface roughness over a range of spatial scales.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        out_mag -- Output raster roughness magnitude file. \n        out_scale -- Output raster roughness scale file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        max_scale -- Maximum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--out_mag='{}'\".format(out_mag))\n        args.append(\"--out_scale='{}'\".format(out_scale))\n        args.append(\"--min_scale={}\".format(min_scale))\n        args.append(\"--max_scale='{}'\".format(max_scale))\n        args.append(\"--step={}\".format(step))\n        return self.run_tool('multiscale_roughness', args, callback) # returns 1 if error\n\n    def multiscale_roughness_signature(self, dem, points, output, max_scale, min_scale=1, step=1, callback=None):\n        \"\"\"Calculates the surface roughness for points over a range of spatial scales.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        points -- Input vector points file. \n        output -- Output HTML file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        max_scale -- Maximum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--points='{}'\".format(points))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--min_scale={}\".format(min_scale))\n        args.append(\"--max_scale='{}'\".format(max_scale))\n        args.append(\"--step={}\".format(step))\n        return self.run_tool('multiscale_roughness_signature', args, callback) # returns 1 if error\n\n    def multiscale_std_dev_normals(self, dem, out_mag, out_scale, min_scale=1, step=1, num_steps=10, step_nonlinearity=1.0, callback=None):\n        \"\"\"Calculates surface roughness over a range of spatial scales.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        out_mag -- Output raster roughness magnitude file. \n        out_scale -- Output raster roughness scale file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        num_steps -- Number of steps. \n        step_nonlinearity -- Step nonlinearity factor (1.0-2.0 is typical). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--out_mag='{}'\".format(out_mag))\n        args.append(\"--out_scale='{}'\".format(out_scale))\n        args.append(\"--min_scale={}\".format(min_scale))\n        args.append(\"--step={}\".format(step))\n        args.append(\"--num_steps={}\".format(num_steps))\n        args.append(\"--step_nonlinearity={}\".format(step_nonlinearity))\n        return self.run_tool('multiscale_std_dev_normals', args, callback) # returns 1 if error\n\n    def multiscale_std_dev_normals_signature(self, dem, points, output, min_scale=1, step=1, num_steps=10, step_nonlinearity=1.0, callback=None):\n        \"\"\"Calculates the surface roughness for points over a range of spatial scales.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        points -- Input vector points file. \n        output -- Output HTML file. \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        step -- Step size as any positive non-zero integer. \n        num_steps -- Number of steps. \n        step_nonlinearity -- Step nonlinearity factor (1.0-2.0 is typical). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--points='{}'\".format(points))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--min_scale={}\".format(min_scale))\n        args.append(\"--step={}\".format(step))\n        args.append(\"--num_steps={}\".format(num_steps))\n        args.append(\"--step_nonlinearity={}\".format(step_nonlinearity))\n        return self.run_tool('multiscale_std_dev_normals_signature', args, callback) # returns 1 if error\n\n    def multiscale_topographic_position_image(self, local, meso, broad, output, hillshade=None, lightness=1.2, callback=None):\n        \"\"\"Creates a multiscale topographic position image from three DEVmax rasters of differing spatial scale ranges.\n\n        Keyword arguments:\n\n        local -- Input local-scale topographic position (DEVmax) raster file. \n        meso -- Input meso-scale topographic position (DEVmax) raster file. \n        broad -- Input broad-scale topographic position (DEVmax) raster file. \n        hillshade -- Input optional hillshade raster file. Note: a multi-directional (360-degree option) hillshade tends to work best in this application. \n        output -- Output raster file. \n        lightness -- Image lightness value (default is 1.2). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--local='{}'\".format(local))\n        args.append(\"--meso='{}'\".format(meso))\n        args.append(\"--broad='{}'\".format(broad))\n        if hillshade is not None: args.append(\"--hillshade='{}'\".format(hillshade))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--lightness={}\".format(lightness))\n        return self.run_tool('multiscale_topographic_position_image', args, callback) # returns 1 if error\n\n    def num_downslope_neighbours(self, dem, output, callback=None):\n        \"\"\"Calculates the number of downslope neighbours to each grid cell in a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('num_downslope_neighbours', args, callback) # returns 1 if error\n\n    def num_upslope_neighbours(self, dem, output, callback=None):\n        \"\"\"Calculates the number of upslope neighbours to each grid cell in a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('num_upslope_neighbours', args, callback) # returns 1 if error\n\n    def openness(self, i, pos_output, neg_output, dist=20, callback=None):\n        \"\"\"This tool calculates the topographic openness index from an input DEM.\n\n        Keyword arguments:\n\n        i -- Name of the input raster DEM file. \n        pos_output -- Name of the positive openness output raster file. \n        neg_output -- Name of the negative openness output raster file. \n        dist -- Search distance, in grid cells. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--pos_output='{}'\".format(pos_output))\n        args.append(\"--neg_output='{}'\".format(neg_output))\n        args.append(\"--dist={}\".format(dist))\n        return self.run_tool('openness', args, callback) # returns 1 if error\n\n    def pennock_landform_class(self, dem, output, slope=3.0, prof=0.1, plan=0.0, zfactor=None, callback=None):\n        \"\"\"Classifies hillslope zones based on slope, profile curvature, and plan curvature.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        slope -- Slope threshold value, in degrees (default is 3.0). \n        prof -- Profile curvature threshold value (default is 0.1). \n        plan -- Plan curvature threshold value (default is 0.0). \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--slope={}\".format(slope))\n        args.append(\"--prof={}\".format(prof))\n        args.append(\"--plan={}\".format(plan))\n        if zfactor is not None: args.append(\"--zfactor='{}'\".format(zfactor))\n        return self.run_tool('pennock_landform_class', args, callback) # returns 1 if error\n\n    def percent_elev_range(self, dem, output, filterx=3, filtery=3, callback=None):\n        \"\"\"Calculates percent of elevation range from a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('percent_elev_range', args, callback) # returns 1 if error\n\n    def plan_curvature(self, dem, output, log=False, zfactor=None, callback=None):\n        \"\"\"Calculates a plan (contour) curvature raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        log -- Display output values using a log-scale. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        if zfactor is not None: args.append(\"--zfactor='{}'\".format(zfactor))\n        return self.run_tool('plan_curvature', args, callback) # returns 1 if error\n\n    def profile(self, lines, surface, output, callback=None):\n        \"\"\"Plots profiles from digital surface models.\n\n        Keyword arguments:\n\n        lines -- Input vector line file. \n        surface -- Input raster surface file. \n        output -- Output HTML file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--lines='{}'\".format(lines))\n        args.append(\"--surface='{}'\".format(surface))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('profile', args, callback) # returns 1 if error\n\n    def profile_curvature(self, dem, output, log=False, zfactor=None, callback=None):\n        \"\"\"Calculates a profile curvature raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        log -- Display output values using a log-scale. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        if zfactor is not None: args.append(\"--zfactor='{}'\".format(zfactor))\n        return self.run_tool('profile_curvature', args, callback) # returns 1 if error\n\n    def relative_aspect(self, dem, output, azimuth=0.0, zfactor=None, callback=None):\n        \"\"\"Calculates relative aspect (relative to a user-specified direction) from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        azimuth -- Illumination source azimuth. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--azimuth={}\".format(azimuth))\n        if zfactor is not None: args.append(\"--zfactor='{}'\".format(zfactor))\n        return self.run_tool('relative_aspect', args, callback) # returns 1 if error\n\n    def relative_topographic_position(self, dem, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Calculates the relative topographic position index from a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('relative_topographic_position', args, callback) # returns 1 if error\n\n    def remove_off_terrain_objects(self, dem, output, filter=11, slope=15.0, callback=None):\n        \"\"\"Removes off-terrain objects from a raster digital elevation model (DEM).\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filter -- Filter size (cells). \n        slope -- Slope threshold value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        args.append(\"--slope={}\".format(slope))\n        return self.run_tool('remove_off_terrain_objects', args, callback) # returns 1 if error\n\n    def ring_curvature(self, dem, output, log=False, zfactor=1.0, callback=None):\n        \"\"\"This tool calculates ring curvature from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Name of the input raster DEM file. \n        output -- Name of the output raster image file. \n        log -- Display output values using a log-scale. \n        zfactor -- Z conversion factor. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('ring_curvature', args, callback) # returns 1 if error\n\n    def rotor(self, dem, output, log=False, zfactor=1.0, callback=None):\n        \"\"\"This tool calculates rotor from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Name of the input raster DEM file. \n        output -- Name of the output raster image file. \n        log -- Display output values using a log-scale. \n        zfactor -- Z conversion factor. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('rotor', args, callback) # returns 1 if error\n\n    def ruggedness_index(self, dem, output, callback=None):\n        \"\"\"Calculates the Riley et al.'s (1999) terrain ruggedness index from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('ruggedness_index', args, callback) # returns 1 if error\n\n    def sediment_transport_index(self, sca, slope, output, sca_exponent=0.4, slope_exponent=1.3, callback=None):\n        \"\"\"Calculates the sediment transport index.\n\n        Keyword arguments:\n\n        sca -- Input raster specific contributing area (SCA) file. \n        slope -- Input raster slope file. \n        output -- Output raster file. \n        sca_exponent -- SCA exponent value. \n        slope_exponent -- Slope exponent value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--sca='{}'\".format(sca))\n        args.append(\"--slope='{}'\".format(slope))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--sca_exponent={}\".format(sca_exponent))\n        args.append(\"--slope_exponent={}\".format(slope_exponent))\n        return self.run_tool('sediment_transport_index', args, callback) # returns 1 if error\n\n    def shadow_animation(self, i, output, palette=\"atlas\", max_dist=\"\", date=\"21/06/2021\", interval=15, location=\"43.5448/-80.2482/-4\", height=600, delay=250, label=\"\", callback=None):\n        \"\"\"This tool creates an animated GIF of shadows based on an input DEM.\n\n        Keyword arguments:\n\n        i -- Name of the input digital surface model (DSM) raster file. \n        palette -- DSM image palette; options are 'atlas', 'high_relief', 'arid', 'soft', 'muted', 'light_quant', 'purple', 'viridis', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep', and 'none'. \n        output -- Name of the output HTML file (*.html). \n        max_dist -- Optional maximum search distance, in xy units. Minimum value is 5 x cell size. \n        date -- Date in format DD/MM/YYYY. \n        interval -- Time interval, in minutes (1-60). \n        location -- Location, defined as Lat/Long/UTC-offset (e.g. 43.5448/-80.2482/-4). \n        height -- Image height, in pixels. \n        delay -- GIF time delay in milliseconds. \n        label -- Label text (leave blank for none). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--palette={}\".format(palette))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--max_dist={}\".format(max_dist))\n        args.append(\"--date={}\".format(date))\n        args.append(\"--interval={}\".format(interval))\n        args.append(\"--location={}\".format(location))\n        args.append(\"--height={}\".format(height))\n        args.append(\"--delay={}\".format(delay))\n        args.append(\"--label={}\".format(label))\n        return self.run_tool('shadow_animation', args, callback) # returns 1 if error\n\n    def shadow_image(self, i, output, palette=\"soft\", max_dist=\"\", date=\"21/06/2021\", time=\"13:00\", location=\"43.5448/-80.2482/-4\", callback=None):\n        \"\"\"This tool creates a raster of shadow areas based on an input DEM.\n\n        Keyword arguments:\n\n        i -- Name of the input digital surface model (DSM) raster file. \n        palette -- DSM image palette; options are 'atlas', 'high_relief', 'arid', 'soft', 'muted', 'light_quant', 'purple', 'viridi', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep', and 'none'. \n        output -- Name of the output raster file. \n        max_dist -- Optional maximum search distance, in xy unites. Minimum value is 5 x cell size. \n        date -- Date in format DD/MM/YYYY. \n        time -- Time in format HH::MM, e.g. 03:15AM or 14:30. \n        location -- Location, defined as Lat/Long/UTC-offset (e.g. 43.5448/-80.2482/-4). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--palette={}\".format(palette))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--max_dist={}\".format(max_dist))\n        args.append(\"--date={}\".format(date))\n        args.append(\"--time={}\".format(time))\n        args.append(\"--location={}\".format(location))\n        return self.run_tool('shadow_image', args, callback) # returns 1 if error\n\n    def shape_index(self, dem, output, zfactor=1.0, callback=None):\n        \"\"\"This tool calculates the shape index from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Name of the input raster DEM file. \n        output -- Name of the output raster image file. \n        zfactor -- Z conversion factor. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('shape_index', args, callback) # returns 1 if error\n\n    def slope(self, dem, output, zfactor=None, units=\"degrees\", callback=None):\n        \"\"\"Calculates a slope raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        units -- Units of output raster; options include 'degrees', 'radians', 'percent'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if zfactor is not None: args.append(\"--zfactor='{}'\".format(zfactor))\n        args.append(\"--units={}\".format(units))\n        return self.run_tool('slope', args, callback) # returns 1 if error\n\n    def slope_vs_aspect_plot(self, i, output, bin_size=2.0, min_slope=0.1, zfactor=1.0, callback=None):\n        \"\"\"This tool creates a slope-aspect relation plot from an input DEM.\n\n        Keyword arguments:\n\n        i -- Name of the input raster image file. \n        output -- Name of the output report file (*.html). \n        bin_size -- Aspect bin size, in degrees. \n        min_slope -- Minimum slope, in degrees. \n        zfactor -- Z conversion factor. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--bin_size={}\".format(bin_size))\n        args.append(\"--min_slope={}\".format(min_slope))\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('slope_vs_aspect_plot', args, callback) # returns 1 if error\n\n    def slope_vs_elevation_plot(self, inputs, output, watershed=None, callback=None):\n        \"\"\"Creates a slope vs. elevation plot for one or more DEMs.\n\n        Keyword arguments:\n\n        inputs -- Input DEM files. \n        watershed -- Input watershed files (optional). \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        if watershed is not None: args.append(\"--watershed='{}'\".format(watershed))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('slope_vs_elevation_plot', args, callback) # returns 1 if error\n\n    def smooth_vegetation_residual(self, i, output, max_scale=30, dev_threshold=1.0, scale_threshold=5, callback=None):\n        \"\"\"This tool can smooth the residual roughness due to vegetation cover in LiDAR DEMs.\n\n        Keyword arguments:\n\n        i -- Name of the input digital elevation model (DEM) raster file. \n        output -- Name of the output raster file. \n        max_scale -- Maximum search neighbourhood radius in grid cells. \n        dev_threshold -- DEVmax Threshold. \n        scale_threshold -- DEVmax scale threshold. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--max_scale={}\".format(max_scale))\n        args.append(\"--dev_threshold={}\".format(dev_threshold))\n        args.append(\"--scale_threshold={}\".format(scale_threshold))\n        return self.run_tool('smooth_vegetation_residual', args, callback) # returns 1 if error\n\n    def spherical_std_dev_of_normals(self, dem, output, filter=11, callback=None):\n        \"\"\"Calculates the spherical standard deviation of surface normals for a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        filter -- Size of the filter kernel. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        return self.run_tool('spherical_std_dev_of_normals', args, callback) # returns 1 if error\n\n    def standard_deviation_of_slope(self, i, output, zfactor=None, filterx=11, filtery=11, callback=None):\n        \"\"\"Calculates the standard deviation of slope from an input DEM.\n\n        Keyword arguments:\n\n        i -- Input raster DEM file. \n        output -- Output raster DEM file. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if zfactor is not None: args.append(\"--zfactor='{}'\".format(zfactor))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('standard_deviation_of_slope', args, callback) # returns 1 if error\n\n    def stream_power_index(self, sca, slope, output, exponent=1.0, callback=None):\n        \"\"\"Calculates the relative stream power index.\n\n        Keyword arguments:\n\n        sca -- Input raster specific contributing area (SCA) file. \n        slope -- Input raster slope file. \n        output -- Output raster file. \n        exponent -- SCA exponent value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--sca='{}'\".format(sca))\n        args.append(\"--slope='{}'\".format(slope))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--exponent={}\".format(exponent))\n        return self.run_tool('stream_power_index', args, callback) # returns 1 if error\n\n    def surface_area_ratio(self, dem, output, callback=None):\n        \"\"\"Calculates a the surface area ratio of each grid cell in an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('surface_area_ratio', args, callback) # returns 1 if error\n\n    def tangential_curvature(self, dem, output, log=False, zfactor=None, callback=None):\n        \"\"\"Calculates a tangential curvature raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        log -- Display output values using a log-scale. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        if zfactor is not None: args.append(\"--zfactor='{}'\".format(zfactor))\n        return self.run_tool('tangential_curvature', args, callback) # returns 1 if error\n\n    def time_in_daylight(self, dem, output, lat, long, az_fraction=10.0, max_dist=100.0, utc_offset=\"00:00\", start_day=1, end_day=365, start_time=\"00:00:00\", end_time=\"23:59:59\", callback=None):\n        \"\"\"Calculates the proportion of time a location is not within an area of shadow.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        az_fraction -- Azimuth fraction in degrees. \n        max_dist -- Optional maximum search distance. Minimum value is 5 x cell size. \n        lat -- Centre point latitude. \n        long -- Centre point longitude. \n        utc_offset -- UTC time offset, in hours (e.g. -04:00, +06:00). \n        start_day -- Start day of the year (1-365). \n        end_day -- End day of the year (1-365). \n        start_time -- Starting hour to track shadows (e.g. 5, 5:00, 05:00:00). Assumes 24-hour time: HH:MM:SS. 'sunrise' is also a valid time. \n        end_time -- Ending hour to track shadows (e.g. 21, 21:00, 21:00:00). Assumes 24-hour time: HH:MM:SS. 'sunset' is also a valid time. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--az_fraction={}\".format(az_fraction))\n        args.append(\"--max_dist={}\".format(max_dist))\n        args.append(\"--lat='{}'\".format(lat))\n        args.append(\"--long='{}'\".format(long))\n        args.append(\"--utc_offset={}\".format(utc_offset))\n        args.append(\"--start_day={}\".format(start_day))\n        args.append(\"--end_day={}\".format(end_day))\n        args.append(\"--start_time={}\".format(start_time))\n        args.append(\"--end_time={}\".format(end_time))\n        return self.run_tool('time_in_daylight', args, callback) # returns 1 if error\n\n    def topo_render(self, dem, output, palette=\"soft\", rev_palette=False, az=315.0, alt=30.0, background_hgt_offset=10.0, polygon=None, background_clr=\"[255, 255, 255]\", attenuation=0.6, ambient_light=0.2, z_factor=1.0, callback=None):\n        \"\"\"This tool creates a pseudo-3D rendering from an input DEM, for the purpose of effective topographic visualization.\n\n        Keyword arguments:\n\n        dem -- Name of the input digital elevation model (DEM) raster file. \n        output -- Name of the output raster file. \n        palette -- Palette name; options are 'atlas', 'high_relief', 'arid', 'soft', 'earthtones', 'muted', 'light_quant', 'purple', 'viridi', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep', 'imhof', and 'white'. \n        rev_palette -- Reverse the palette?. \n        az -- Light source azimuth direction (degrees, 0-360). \n        alt -- Light source altitude (degrees, 0-90). \n        background_hgt_offset -- Offset height of background, in z-units. \n        polygon -- Clipping polygon vector file (optional). \n        background_clr -- Background red-green-blue (RGB) or red-green-blue-alpha (RGBA) colour, e.g. '[255, 255, 245]', '[255, 255, 245, 200]'. \n        attenuation -- Attenuation parameter. Range is 0-4. Zero means no attenuation. \n        ambient_light -- Ambient light parameter. Range is 0.0-0.7. Zero means no ambient light. \n        z_factor -- Elevation multiplier, or a vertical exageration. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--palette={}\".format(palette))\n        if rev_palette: args.append(\"--rev_palette\")\n        args.append(\"--az={}\".format(az))\n        args.append(\"--alt={}\".format(alt))\n        args.append(\"--background_hgt_offset={}\".format(background_hgt_offset))\n        if polygon is not None: args.append(\"--polygon='{}'\".format(polygon))\n        args.append(\"--background_clr={}\".format(background_clr))\n        args.append(\"--attenuation={}\".format(attenuation))\n        args.append(\"--ambient_light={}\".format(ambient_light))\n        args.append(\"--z_factor={}\".format(z_factor))\n        return self.run_tool('topo_render', args, callback) # returns 1 if error\n\n    def topographic_position_animation(self, i, output, palette=\"bl_yl_rd\", min_scale=1, num_steps=100, step_nonlinearity=1.5, height=600, delay=250, label=\"\", dev_max=False, callback=None):\n        \"\"\"This tool creates an animated GIF of multi-scale local topographic position (elevation deviation).\n\n        Keyword arguments:\n\n        i -- Name of the input digital elevation model (DEM) raster file. \n        palette -- Image palette; options are 'bl_yl_rd', 'bl_w_rd', 'purple', 'gn_yl', 'pi_y_g', and 'viridis'. \n        output -- Name of the output HTML file (*.html). \n        min_scale -- Minimum search neighbourhood radius in grid cells. \n        num_steps -- Number of steps. \n        step_nonlinearity -- Step nonlinearity factor (1.0-2.0 is typical). \n        height -- Image height, in pixels. \n        delay -- GIF time delay in milliseconds. \n        label -- Label text (leave blank for none). \n        dev_max -- Do you want to use DEVmax instead of DEV for measuring local topographic position?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--palette={}\".format(palette))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--min_scale={}\".format(min_scale))\n        args.append(\"--num_steps={}\".format(num_steps))\n        args.append(\"--step_nonlinearity={}\".format(step_nonlinearity))\n        args.append(\"--height={}\".format(height))\n        args.append(\"--delay={}\".format(delay))\n        args.append(\"--label={}\".format(label))\n        if dev_max: args.append(\"--dev_max\")\n        return self.run_tool('topographic_position_animation', args, callback) # returns 1 if error\n\n    def total_curvature(self, dem, output, log=False, zfactor=None, callback=None):\n        \"\"\"Calculates a total curvature raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        log -- Display output values using a log-scale. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        if zfactor is not None: args.append(\"--zfactor='{}'\".format(zfactor))\n        return self.run_tool('total_curvature', args, callback) # returns 1 if error\n\n    def unsphericity(self, dem, output, log=False, zfactor=1.0, callback=None):\n        \"\"\"This tool calculates the unsphericity curvature from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Name of the input raster DEM file. \n        output -- Name of the output raster image file. \n        log -- Display output values using a log-scale. \n        zfactor -- Z conversion factor. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('unsphericity', args, callback) # returns 1 if error\n\n    def vertical_excess_curvature(self, dem, output, log=False, zfactor=1.0, callback=None):\n        \"\"\"This tool calculates vertical excess curvature from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Name of the input raster DEM file. \n        output -- Name of the output raster image file. \n        log -- Display output values using a log-scale. \n        zfactor -- Z conversion factor. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if log: args.append(\"--log\")\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('vertical_excess_curvature', args, callback) # returns 1 if error\n\n    def viewshed(self, dem, stations, output, height=2.0, callback=None):\n        \"\"\"Identifies the viewshed for a point or set of points.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        stations -- Input viewing station vector file. \n        output -- Output raster file. \n        height -- Viewing station height, in z units. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--stations='{}'\".format(stations))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--height={}\".format(height))\n        return self.run_tool('viewshed', args, callback) # returns 1 if error\n\n    def visibility_index(self, dem, output, height=2.0, res_factor=2, callback=None):\n        \"\"\"Estimates the relative visibility of sites in a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        height -- Viewing station height, in z units. \n        res_factor -- The resolution factor determines the density of measured viewsheds. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--height={}\".format(height))\n        args.append(\"--res_factor={}\".format(res_factor))\n        return self.run_tool('visibility_index', args, callback) # returns 1 if error\n\n    def wetness_index(self, sca, slope, output, callback=None):\n        \"\"\"Calculates the topographic wetness index, Ln(A / tan(slope)).\n\n        Keyword arguments:\n\n        sca -- Input raster specific contributing area (SCA) file. \n        slope -- Input raster slope file (in degrees). \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--sca='{}'\".format(sca))\n        args.append(\"--slope='{}'\".format(slope))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('wetness_index', args, callback) # returns 1 if error\n\n    #########################\n    # Hydrological Analysis #\n    #########################\n\n    def average_flowpath_slope(self, dem, output, callback=None):\n        \"\"\"Measures the average slope gradient from each grid cell to all upslope divide cells.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('average_flowpath_slope', args, callback) # returns 1 if error\n\n    def average_upslope_flowpath_length(self, dem, output, callback=None):\n        \"\"\"Measures the average length of all upslope flowpaths draining each grid cell.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('average_upslope_flowpath_length', args, callback) # returns 1 if error\n\n    def basins(self, d8_pntr, output, esri_pntr=False, callback=None):\n        \"\"\"Identifies drainage basins that drain to the DEM edge.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('basins', args, callback) # returns 1 if error\n\n    def breach_depressions(self, dem, output, max_depth=None, max_length=None, flat_increment=None, fill_pits=False, callback=None):\n        \"\"\"Breaches all of the depressions in a DEM using Lindsay's (2016) algorithm. This should be preferred over depression filling in most cases.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        max_depth -- Optional maximum breach depth (default is Inf). \n        max_length -- Optional maximum breach channel length (in grid cells; default is Inf). \n        flat_increment -- Optional elevation increment applied to flat areas. \n        fill_pits -- Optional flag indicating whether to fill single-cell pits. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if max_depth is not None: args.append(\"--max_depth='{}'\".format(max_depth))\n        if max_length is not None: args.append(\"--max_length='{}'\".format(max_length))\n        if flat_increment is not None: args.append(\"--flat_increment='{}'\".format(flat_increment))\n        if fill_pits: args.append(\"--fill_pits\")\n        return self.run_tool('breach_depressions', args, callback) # returns 1 if error\n\n    def breach_depressions_least_cost(self, dem, output, dist, max_cost=None, min_dist=True, flat_increment=None, fill=True, callback=None):\n        \"\"\"Breaches the depressions in a DEM using a least-cost pathway method.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        dist -- Maximum search distance for breach paths in cells. \n        max_cost -- Optional maximum breach cost (default is Inf). \n        min_dist -- Optional flag indicating whether to minimize breach distances. \n        flat_increment -- Optional elevation increment applied to flat areas. \n        fill -- Optional flag indicating whether to fill any remaining unbreached depressions. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--dist='{}'\".format(dist))\n        if max_cost is not None: args.append(\"--max_cost='{}'\".format(max_cost))\n        if min_dist: args.append(\"--min_dist\")\n        if flat_increment is not None: args.append(\"--flat_increment='{}'\".format(flat_increment))\n        if fill: args.append(\"--fill\")\n        return self.run_tool('breach_depressions_least_cost', args, callback) # returns 1 if error\n\n    def breach_single_cell_pits(self, dem, output, callback=None):\n        \"\"\"Removes single-cell pits from an input DEM by breaching.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('breach_single_cell_pits', args, callback) # returns 1 if error\n\n    def burn_streams_at_roads(self, dem, streams, roads, output, width=None, callback=None):\n        \"\"\"Burns-in streams at the sites of road embankments.\n\n        Keyword arguments:\n\n        dem -- Input raster digital elevation model (DEM) file. \n        streams -- Input vector streams file. \n        roads -- Input vector roads file. \n        output -- Output raster file. \n        width -- Maximum road embankment width, in map units. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--roads='{}'\".format(roads))\n        args.append(\"--output='{}'\".format(output))\n        if width is not None: args.append(\"--width='{}'\".format(width))\n        return self.run_tool('burn_streams_at_roads', args, callback) # returns 1 if error\n\n    def d8_flow_accumulation(self, i, output, out_type=\"cells\", log=False, clip=False, pntr=False, esri_pntr=False, callback=None):\n        \"\"\"Calculates a D8 flow accumulation raster from an input DEM or flow pointer.\n\n        Keyword arguments:\n\n        i -- Input raster DEM or D8 pointer file. \n        output -- Output raster file. \n        out_type -- Output type; one of 'cells' (default), 'catchment area', and 'specific contributing area'. \n        log -- Optional flag to request the output be log-transformed. \n        clip -- Optional flag to request clipping the display max by 1%. \n        pntr -- Is the input raster a D8 flow pointer rather than a DEM?. \n        esri_pntr -- Input D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--out_type={}\".format(out_type))\n        if log: args.append(\"--log\")\n        if clip: args.append(\"--clip\")\n        if pntr: args.append(\"--pntr\")\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('d8_flow_accumulation', args, callback) # returns 1 if error\n\n    def d8_mass_flux(self, dem, loading, efficiency, absorption, output, callback=None):\n        \"\"\"Performs a D8 mass flux calculation.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        loading -- Input loading raster file. \n        efficiency -- Input efficiency raster file. \n        absorption -- Input absorption raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--loading='{}'\".format(loading))\n        args.append(\"--efficiency='{}'\".format(efficiency))\n        args.append(\"--absorption='{}'\".format(absorption))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('d8_mass_flux', args, callback) # returns 1 if error\n\n    def d8_pointer(self, dem, output, esri_pntr=False, callback=None):\n        \"\"\"Calculates a D8 flow pointer raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('d8_pointer', args, callback) # returns 1 if error\n\n    def d_inf_flow_accumulation(self, i, output, out_type=\"Specific Contributing Area\", threshold=None, log=False, clip=False, pntr=False, callback=None):\n        \"\"\"Calculates a D-infinity flow accumulation raster from an input DEM.\n\n        Keyword arguments:\n\n        i -- Input raster DEM or D-infinity pointer file. \n        output -- Output raster file. \n        out_type -- Output type; one of 'cells', 'sca' (default), and 'ca'. \n        threshold -- Optional convergence threshold parameter, in grid cells; default is infinity. \n        log -- Optional flag to request the output be log-transformed. \n        clip -- Optional flag to request clipping the display max by 1%. \n        pntr -- Is the input raster a D-infinity flow pointer rather than a DEM?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--out_type={}\".format(out_type))\n        if threshold is not None: args.append(\"--threshold='{}'\".format(threshold))\n        if log: args.append(\"--log\")\n        if clip: args.append(\"--clip\")\n        if pntr: args.append(\"--pntr\")\n        return self.run_tool('d_inf_flow_accumulation', args, callback) # returns 1 if error\n\n    def d_inf_mass_flux(self, dem, loading, efficiency, absorption, output, callback=None):\n        \"\"\"Performs a D-infinity mass flux calculation.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        loading -- Input loading raster file. \n        efficiency -- Input efficiency raster file. \n        absorption -- Input absorption raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--loading='{}'\".format(loading))\n        args.append(\"--efficiency='{}'\".format(efficiency))\n        args.append(\"--absorption='{}'\".format(absorption))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('d_inf_mass_flux', args, callback) # returns 1 if error\n\n    def d_inf_pointer(self, dem, output, callback=None):\n        \"\"\"Calculates a D-infinity flow pointer (flow direction) raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('d_inf_pointer', args, callback) # returns 1 if error\n\n    def depth_in_sink(self, dem, output, zero_background=False, callback=None):\n        \"\"\"Measures the depth of sinks (depressions) in a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        zero_background -- Flag indicating whether the background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('depth_in_sink', args, callback) # returns 1 if error\n\n    def depth_to_water(self, dem, output, streams=None, lakes=None, callback=None):\n        \"\"\"This tool calculates cartographic depth-to-water (DTW) index.\n\n        Keyword arguments:\n\n        dem -- Name of the input raster DEM file. \n        streams -- Name of the input streams vector (optional). \n        lakes -- Name of the input lakes vector (optional). \n        output -- Name of the output raster image file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        if streams is not None: args.append(\"--streams='{}'\".format(streams))\n        if lakes is not None: args.append(\"--lakes='{}'\".format(lakes))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('depth_to_water', args, callback) # returns 1 if error\n\n    def downslope_distance_to_stream(self, dem, streams, output, dinf=False, callback=None):\n        \"\"\"Measures distance to the nearest downslope stream cell.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        dinf -- Use the D-infinity flow algorithm instead of D8?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if dinf: args.append(\"--dinf\")\n        return self.run_tool('downslope_distance_to_stream', args, callback) # returns 1 if error\n\n    def downslope_flowpath_length(self, d8_pntr, output, watersheds=None, weights=None, esri_pntr=False, callback=None):\n        \"\"\"Calculates the downslope flowpath length from each cell to basin outlet.\n\n        Keyword arguments:\n\n        d8_pntr -- Input D8 pointer raster file. \n        watersheds -- Optional input watershed raster file. \n        weights -- Optional input weights raster file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        if watersheds is not None: args.append(\"--watersheds='{}'\".format(watersheds))\n        if weights is not None: args.append(\"--weights='{}'\".format(weights))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('downslope_flowpath_length', args, callback) # returns 1 if error\n\n    def edge_contamination(self, dem, output, flow_type=\"mfd\", zfactor=\"\", callback=None):\n        \"\"\"Identifies grid cells within an input DEM that may be impacted by edge contamination for hydrological applications.\n\n        Keyword arguments:\n\n        dem -- Name of the input DEM raster file; must be depressionless. \n        output -- Name of the output raster file. \n        flow_type -- Flow algorithm type, one of 'd8', 'mfd', or 'dinf'. \n        zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--flow_type={}\".format(flow_type))\n        args.append(\"--zfactor={}\".format(zfactor))\n        return self.run_tool('edge_contamination', args, callback) # returns 1 if error\n\n    def elevation_above_stream(self, dem, streams, output, callback=None):\n        \"\"\"Calculates the elevation of cells above the nearest downslope stream cell.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('elevation_above_stream', args, callback) # returns 1 if error\n\n    def elevation_above_stream_euclidean(self, dem, streams, output, callback=None):\n        \"\"\"Calculates the elevation of cells above the nearest (Euclidean distance) stream cell.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('elevation_above_stream_euclidean', args, callback) # returns 1 if error\n\n    def fd8_flow_accumulation(self, dem, output, out_type=\"specific contributing area\", exponent=1.1, threshold=None, log=False, clip=False, callback=None):\n        \"\"\"Calculates an FD8 flow accumulation raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        out_type -- Output type; one of 'cells', 'specific contributing area' (default), and 'catchment area'. \n        exponent -- Optional exponent parameter; default is 1.1. \n        threshold -- Optional convergence threshold parameter, in grid cells; default is infinity. \n        log -- Optional flag to request the output be log-transformed. \n        clip -- Optional flag to request clipping the display max by 1%. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--out_type={}\".format(out_type))\n        args.append(\"--exponent={}\".format(exponent))\n        if threshold is not None: args.append(\"--threshold='{}'\".format(threshold))\n        if log: args.append(\"--log\")\n        if clip: args.append(\"--clip\")\n        return self.run_tool('fd8_flow_accumulation', args, callback) # returns 1 if error\n\n    def fd8_pointer(self, dem, output, callback=None):\n        \"\"\"Calculates an FD8 flow pointer raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('fd8_pointer', args, callback) # returns 1 if error\n\n    def fill_burn(self, dem, streams, output, callback=None):\n        \"\"\"Burns streams into a DEM using the FillBurn (Saunders, 1999) method.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        streams -- Input vector streams file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('fill_burn', args, callback) # returns 1 if error\n\n    def fill_depressions(self, dem, output, fix_flats=True, flat_increment=None, max_depth=None, callback=None):\n        \"\"\"Fills all of the depressions in a DEM. Depression breaching should be preferred in most cases.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        fix_flats -- Optional flag indicating whether flat areas should have a small gradient applied. \n        flat_increment -- Optional elevation increment applied to flat areas. \n        max_depth -- Optional maximum depression depth to fill. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if fix_flats: args.append(\"--fix_flats\")\n        if flat_increment is not None: args.append(\"--flat_increment='{}'\".format(flat_increment))\n        if max_depth is not None: args.append(\"--max_depth='{}'\".format(max_depth))\n        return self.run_tool('fill_depressions', args, callback) # returns 1 if error\n\n    def fill_depressions_planchon_and_darboux(self, dem, output, fix_flats=True, flat_increment=None, callback=None):\n        \"\"\"Fills all of the depressions in a DEM using the Planchon and Darboux (2002) method.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        fix_flats -- Optional flag indicating whether flat areas should have a small gradient applied. \n        flat_increment -- Optional elevation increment applied to flat areas. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if fix_flats: args.append(\"--fix_flats\")\n        if flat_increment is not None: args.append(\"--flat_increment='{}'\".format(flat_increment))\n        return self.run_tool('fill_depressions_planchon_and_darboux', args, callback) # returns 1 if error\n\n    def fill_depressions_wang_and_liu(self, dem, output, fix_flats=True, flat_increment=None, callback=None):\n        \"\"\"Fills all of the depressions in a DEM using the Wang and Liu (2006) method. Depression breaching should be preferred in most cases.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        fix_flats -- Optional flag indicating whether flat areas should have a small gradient applied. \n        flat_increment -- Optional elevation increment applied to flat areas. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if fix_flats: args.append(\"--fix_flats\")\n        if flat_increment is not None: args.append(\"--flat_increment='{}'\".format(flat_increment))\n        return self.run_tool('fill_depressions_wang_and_liu', args, callback) # returns 1 if error\n\n    def fill_single_cell_pits(self, dem, output, callback=None):\n        \"\"\"Raises pit cells to the elevation of their lowest neighbour.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('fill_single_cell_pits', args, callback) # returns 1 if error\n\n    def find_no_flow_cells(self, dem, output, callback=None):\n        \"\"\"Finds grid cells with no downslope neighbours.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('find_no_flow_cells', args, callback) # returns 1 if error\n\n    def find_parallel_flow(self, d8_pntr, streams, output, callback=None):\n        \"\"\"Finds areas of parallel flow in D8 flow direction rasters.\n\n        Keyword arguments:\n\n        d8_pntr -- Input D8 pointer raster file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('find_parallel_flow', args, callback) # returns 1 if error\n\n    def flatten_lakes(self, dem, lakes, output, callback=None):\n        \"\"\"Flattens lake polygons in a raster DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        lakes -- Input lakes vector polygons file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--lakes='{}'\".format(lakes))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('flatten_lakes', args, callback) # returns 1 if error\n\n    def flood_order(self, dem, output, callback=None):\n        \"\"\"Assigns each DEM grid cell its order in the sequence of inundations that are encountered during a search starting from the edges, moving inward at increasing elevations.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('flood_order', args, callback) # returns 1 if error\n\n    def flow_accumulation_full_workflow(self, dem, out_dem, out_pntr, out_accum, out_type=\"Specific Contributing Area\", log=False, clip=False, esri_pntr=False, callback=None):\n        \"\"\"Resolves all of the depressions in a DEM, outputting a breached DEM, an aspect-aligned non-divergent flow pointer, and a flow accumulation raster.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        out_dem -- Output raster DEM file. \n        out_pntr -- Output raster flow pointer file. \n        out_accum -- Output raster flow accumulation file. \n        out_type -- Output type; one of 'cells', 'sca' (default), and 'ca'. \n        log -- Optional flag to request the output be log-transformed. \n        clip -- Optional flag to request clipping the display max by 1%. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--out_dem='{}'\".format(out_dem))\n        args.append(\"--out_pntr='{}'\".format(out_pntr))\n        args.append(\"--out_accum='{}'\".format(out_accum))\n        args.append(\"--out_type={}\".format(out_type))\n        if log: args.append(\"--log\")\n        if clip: args.append(\"--clip\")\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('flow_accumulation_full_workflow', args, callback) # returns 1 if error\n\n    def flow_length_diff(self, d8_pntr, output, esri_pntr=False, callback=None):\n        \"\"\"Calculates the local maximum absolute difference in downslope flowpath length, useful in mapping drainage divides and ridges.\n\n        Keyword arguments:\n\n        d8_pntr -- Input D8 pointer raster file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('flow_length_diff', args, callback) # returns 1 if error\n\n    def hillslopes(self, d8_pntr, streams, output, esri_pntr=False, callback=None):\n        \"\"\"Identifies the individual hillslopes draining to each link in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('hillslopes', args, callback) # returns 1 if error\n\n    def hydrologic_connectivity(self, dem, output1, output2, exponent=1.0, threshold=None, callback=None):\n        \"\"\"This tool evaluates hydrologic connectivity within a DEM.\n\n        Keyword arguments:\n\n        dem -- Name of the input DEM raster file; must be depressionless. \n        output1 -- Name of the output downslope unsaturated length (DUL) file. \n        output2 -- Name of the output upslope disconnected saturated area (UDSA) file. \n        exponent -- Optional exponent parameter; default is 1.0. \n        threshold -- Optional convergence threshold parameter, in grid cells; default is infinity. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output1='{}'\".format(output1))\n        args.append(\"--output2='{}'\".format(output2))\n        args.append(\"--exponent={}\".format(exponent))\n        if threshold is not None: args.append(\"--threshold='{}'\".format(threshold))\n        return self.run_tool('hydrologic_connectivity', args, callback) # returns 1 if error\n\n    def impoundment_size_index(self, dem, damlength, out_mean=None, out_max=None, out_volume=None, out_area=None, out_dam_height=None, callback=None):\n        \"\"\"Calculates the impoundment size resulting from damming a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        out_mean -- Output mean flooded depth file. \n        out_max -- Output maximum flooded depth file. \n        out_volume -- Output flooded volume file. \n        out_area -- Output flooded area file. \n        out_dam_height -- Output dam height file. \n        damlength -- Maximum length of the dam. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        if out_mean is not None: args.append(\"--out_mean='{}'\".format(out_mean))\n        if out_max is not None: args.append(\"--out_max='{}'\".format(out_max))\n        if out_volume is not None: args.append(\"--out_volume='{}'\".format(out_volume))\n        if out_area is not None: args.append(\"--out_area='{}'\".format(out_area))\n        if out_dam_height is not None: args.append(\"--out_dam_height='{}'\".format(out_dam_height))\n        args.append(\"--damlength='{}'\".format(damlength))\n        return self.run_tool('impoundment_size_index', args, callback) # returns 1 if error\n\n    def insert_dams(self, dem, dam_pts, output, damlength, callback=None):\n        \"\"\"Calculates the impoundment size resulting from damming a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        dam_pts -- Input vector dam points file. \n        output -- Output file. \n        damlength -- Maximum length of the dam. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--dam_pts='{}'\".format(dam_pts))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--damlength='{}'\".format(damlength))\n        return self.run_tool('insert_dams', args, callback) # returns 1 if error\n\n    def isobasins(self, dem, output, size, connections=False, callback=None):\n        \"\"\"Divides a landscape into nearly equal sized drainage basins (i.e. watersheds).\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        size -- Target basin size, in grid cells. \n        connections -- Output upstream-downstream flow connections among basins?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--size='{}'\".format(size))\n        if connections: args.append(\"--connections\")\n        return self.run_tool('isobasins', args, callback) # returns 1 if error\n\n    def jenson_snap_pour_points(self, pour_pts, streams, output, snap_dist, callback=None):\n        \"\"\"Moves outlet points used to specify points of interest in a watershedding operation to the nearest stream cell.\n\n        Keyword arguments:\n\n        pour_pts -- Input vector pour points (outlet) file. \n        streams -- Input raster streams file. \n        output -- Output vector file. \n        snap_dist -- Maximum snap distance in map units. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--pour_pts='{}'\".format(pour_pts))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--snap_dist='{}'\".format(snap_dist))\n        return self.run_tool('jenson_snap_pour_points', args, callback) # returns 1 if error\n\n    def longest_flowpath(self, dem, basins, output, callback=None):\n        \"\"\"Delineates the longest flowpaths for a group of subbasins or watersheds.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        basins -- Input raster basins file. \n        output -- Output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--basins='{}'\".format(basins))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('longest_flowpath', args, callback) # returns 1 if error\n\n    def low_points_on_headwater_divides(self, dem, streams, output, callback=None):\n        \"\"\"This tool locates saddle points along ridges within a digital elevation model (DEM).\n\n        Keyword arguments:\n\n        dem -- Name of the input DEM raster file. \n        streams -- Name of the input stream channel raster file. \n        output -- Name of the output vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('low_points_on_headwater_divides', args, callback) # returns 1 if error\n\n    def max_upslope_flowpath_length(self, dem, output, callback=None):\n        \"\"\"Measures the maximum length of all upslope flowpaths draining each grid cell.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('max_upslope_flowpath_length', args, callback) # returns 1 if error\n\n    def max_upslope_value(self, dem, values, output, callback=None):\n        \"\"\"Calculates the maximum upslope value from an input values raster along flowpaths.\n\n        Keyword arguments:\n\n        dem -- Input DEM; it must be depressionless. \n        values -- Name of the input values raster file. \n        output -- Name of the output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--values='{}'\".format(values))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('max_upslope_value', args, callback) # returns 1 if error\n\n    def md_inf_flow_accumulation(self, dem, output, out_type=\"specific contributing area\", exponent=1.1, threshold=None, log=False, clip=False, callback=None):\n        \"\"\"Calculates an FD8 flow accumulation raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        out_type -- Output type; one of 'cells', 'specific contributing area' (default), and 'catchment area'. \n        exponent -- Optional exponent parameter; default is 1.1. \n        threshold -- Optional convergence threshold parameter, in grid cells; default is infinity. \n        log -- Optional flag to request the output be log-transformed. \n        clip -- Optional flag to request clipping the display max by 1%. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--out_type={}\".format(out_type))\n        args.append(\"--exponent={}\".format(exponent))\n        if threshold is not None: args.append(\"--threshold='{}'\".format(threshold))\n        if log: args.append(\"--log\")\n        if clip: args.append(\"--clip\")\n        return self.run_tool('md_inf_flow_accumulation', args, callback) # returns 1 if error\n\n    def num_inflowing_neighbours(self, dem, output, callback=None):\n        \"\"\"Computes the number of inflowing neighbours to each cell in an input DEM based on the D8 algorithm.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('num_inflowing_neighbours', args, callback) # returns 1 if error\n\n    def qin_flow_accumulation(self, dem, output, out_type=\"specific contributing area\", exponent=10.0, max_slope=45.0, threshold=None, log=False, clip=False, callback=None):\n        \"\"\"Calculates Qin et al. (2007) flow accumulation.\n\n        Keyword arguments:\n\n        dem -- Name of the input DEM raster file; must be depressionless. \n        output -- Name of the output raster file. \n        out_type -- Output type; one of 'cells', 'specific contributing area' (default), and 'catchment area'. \n        exponent -- Optional upper-bound exponent parameter; default is 10.0. \n        max_slope -- Optional upper-bound slope parameter, in degrees (0-90); default is 45.0. \n        threshold -- Optional convergence threshold parameter, in grid cells; default is infinity. \n        log -- Log-transform the output values?. \n        clip -- Optional flag to request clipping the display max by 1%. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--out_type={}\".format(out_type))\n        args.append(\"--exponent={}\".format(exponent))\n        args.append(\"--max_slope={}\".format(max_slope))\n        if threshold is not None: args.append(\"--threshold='{}'\".format(threshold))\n        if log: args.append(\"--log\")\n        if clip: args.append(\"--clip\")\n        return self.run_tool('qin_flow_accumulation', args, callback) # returns 1 if error\n\n    def quinn_flow_accumulation(self, dem, output, out_type=\"specific contributing area\", exponent=1.0, threshold=None, log=False, clip=False, callback=None):\n        \"\"\"Calculates Quinn et al. (1995) flow accumulation.\n\n        Keyword arguments:\n\n        dem -- Name of the input DEM raster file; must be depressionless. \n        output -- Name of the output raster file. \n        out_type -- Output type; one of 'cells', 'specific contributing area' (default), and 'catchment area'. \n        exponent -- Optional exponent parameter; default is 1.0. \n        threshold -- Optional convergence threshold parameter, in grid cells; default is infinity. \n        log -- Log-transform the output values?. \n        clip -- Optional flag to request clipping the display max by 1%. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--out_type={}\".format(out_type))\n        args.append(\"--exponent={}\".format(exponent))\n        if threshold is not None: args.append(\"--threshold='{}'\".format(threshold))\n        if log: args.append(\"--log\")\n        if clip: args.append(\"--clip\")\n        return self.run_tool('quinn_flow_accumulation', args, callback) # returns 1 if error\n\n    def raise_walls(self, i, dem, output, breach=None, height=100.0, callback=None):\n        \"\"\"Raises walls in a DEM along a line or around a polygon, e.g. a watershed.\n\n        Keyword arguments:\n\n        i -- Input vector lines or polygons file. \n        breach -- Optional input vector breach lines. \n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        height -- Wall height. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if breach is not None: args.append(\"--breach='{}'\".format(breach))\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--height={}\".format(height))\n        return self.run_tool('raise_walls', args, callback) # returns 1 if error\n\n    def rho8_flow_accumulation(self, i, output, out_type=\"specific contributing area\", log=False, clip=False, pntr=False, esri_pntr=False, callback=None):\n        \"\"\"Calculates Fairfield and Leymarie (1991) flow accumulation.\n\n        Keyword arguments:\n\n        i -- Input DEM or Rho8 pointer file; if a DEM is used, it must be depressionless. \n        output -- Name of the output raster file. \n        out_type -- Output type; one of 'cells', 'specific contributing area' (default), and 'catchment area'. \n        log -- Log-transform the output values?. \n        clip -- Optional flag to request clipping the display max by 1%. \n        pntr -- Is the input raster a Rho8 flow pointer rather than a DEM?. \n        esri_pntr -- Does the input Rho8 pointer use the ESRI style scheme?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--out_type={}\".format(out_type))\n        if log: args.append(\"--log\")\n        if clip: args.append(\"--clip\")\n        if pntr: args.append(\"--pntr\")\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('rho8_flow_accumulation', args, callback) # returns 1 if error\n\n    def rho8_pointer(self, dem, output, esri_pntr=False, callback=None):\n        \"\"\"Calculates a stochastic Rho8 flow pointer raster from an input DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('rho8_pointer', args, callback) # returns 1 if error\n\n    def river_centerlines(self, i, output, min_length=3, radius=4, callback=None):\n        \"\"\"Maps river centerlines from an input water raster.\n\n        Keyword arguments:\n\n        i -- Name of the input raster image file. \n        output -- Name of the output vector lines file. \n        min_length -- Minimum line length, in grid cells. \n        radius -- Search radius for joining distant endnodes, in grid cells. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--min_length={}\".format(min_length))\n        args.append(\"--radius={}\".format(radius))\n        return self.run_tool('river_centerlines', args, callback) # returns 1 if error\n\n    def sink(self, i, output, zero_background=False, callback=None):\n        \"\"\"Identifies the depressions in a DEM, giving each feature a unique identifier.\n\n        Keyword arguments:\n\n        i -- Input raster DEM file. \n        output -- Output raster file. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('sink', args, callback) # returns 1 if error\n\n    def snap_pour_points(self, pour_pts, flow_accum, output, snap_dist, callback=None):\n        \"\"\"Moves outlet points used to specify points of interest in a watershedding operation to the cell with the highest flow accumulation in its neighbourhood.\n\n        Keyword arguments:\n\n        pour_pts -- Input vector pour points (outlet) file. \n        flow_accum -- Input raster D8 flow accumulation file. \n        output -- Output vector file. \n        snap_dist -- Maximum snap distance in map units. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--pour_pts='{}'\".format(pour_pts))\n        args.append(\"--flow_accum='{}'\".format(flow_accum))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--snap_dist='{}'\".format(snap_dist))\n        return self.run_tool('snap_pour_points', args, callback) # returns 1 if error\n\n    def stochastic_depression_analysis(self, dem, output, rmse, range, iterations=100, callback=None):\n        \"\"\"Performs a stochastic analysis of depressions within a DEM.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output file. \n        rmse -- The DEM's root-mean-square-error (RMSE), in z units. This determines error magnitude. \n        range -- The error field's correlation length, in xy-units. \n        iterations -- The number of iterations. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--rmse='{}'\".format(rmse))\n        args.append(\"--range='{}'\".format(range))\n        args.append(\"--iterations={}\".format(iterations))\n        return self.run_tool('stochastic_depression_analysis', args, callback) # returns 1 if error\n\n    def strahler_order_basins(self, d8_pntr, streams, output, esri_pntr=False, callback=None):\n        \"\"\"Identifies Strahler-order basins from an input stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('strahler_order_basins', args, callback) # returns 1 if error\n\n    def subbasins(self, d8_pntr, streams, output, esri_pntr=False, callback=None):\n        \"\"\"Identifies the catchments, or sub-basin, draining to each link in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input D8 pointer raster file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('subbasins', args, callback) # returns 1 if error\n\n    def trace_downslope_flowpaths(self, seed_pts, d8_pntr, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Traces downslope flowpaths from one or more target sites (i.e. seed points).\n\n        Keyword arguments:\n\n        seed_pts -- Input vector seed points file. \n        d8_pntr -- Input D8 pointer raster file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--seed_pts='{}'\".format(seed_pts))\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('trace_downslope_flowpaths', args, callback) # returns 1 if error\n\n    def unnest_basins(self, d8_pntr, pour_pts, output, esri_pntr=False, callback=None):\n        \"\"\"Extract whole watersheds for a set of outlet points.\n\n        Keyword arguments:\n\n        d8_pntr -- Input D8 pointer raster file. \n        pour_pts -- Input vector pour points (outlet) file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--pour_pts='{}'\".format(pour_pts))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('unnest_basins', args, callback) # returns 1 if error\n\n    def upslope_depression_storage(self, dem, output, callback=None):\n        \"\"\"Estimates the average upslope depression storage depth.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('upslope_depression_storage', args, callback) # returns 1 if error\n\n    def watershed(self, d8_pntr, pour_pts, output, esri_pntr=False, callback=None):\n        \"\"\"Identifies the watershed, or drainage basin, draining to a set of target cells.\n\n        Keyword arguments:\n\n        d8_pntr -- Input D8 pointer raster file. \n        pour_pts -- Input pour points (outlet) file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--pour_pts='{}'\".format(pour_pts))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('watershed', args, callback) # returns 1 if error\n\n    ##########################\n    # Image Processing Tools #\n    ##########################\n\n    def change_vector_analysis(self, date1, date2, magnitude, direction, callback=None):\n        \"\"\"Performs a change vector analysis on a two-date multi-spectral dataset.\n\n        Keyword arguments:\n\n        date1 -- Input raster files for the earlier date. \n        date2 -- Input raster files for the later date. \n        magnitude -- Output vector magnitude raster file. \n        direction -- Output vector Direction raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--date1='{}'\".format(date1))\n        args.append(\"--date2='{}'\".format(date2))\n        args.append(\"--magnitude='{}'\".format(magnitude))\n        args.append(\"--direction='{}'\".format(direction))\n        return self.run_tool('change_vector_analysis', args, callback) # returns 1 if error\n\n    def closing(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"A closing is a mathematical morphology operation involving an erosion (min filter) of a dilation (max filter) set.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('closing', args, callback) # returns 1 if error\n\n    def create_colour_composite(self, red, green, blue, output, opacity=None, enhance=True, zeros=False, callback=None):\n        \"\"\"Creates a colour-composite image from three bands of multispectral imagery.\n\n        Keyword arguments:\n\n        red -- Input red band image file. \n        green -- Input green band image file. \n        blue -- Input blue band image file. \n        opacity -- Input opacity band image file (optional). \n        output -- Output colour composite file. \n        enhance -- Optional flag indicating whether a balance contrast enhancement is performed. \n        zeros -- Optional flag to indicate if zeros are nodata values. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--red='{}'\".format(red))\n        args.append(\"--green='{}'\".format(green))\n        args.append(\"--blue='{}'\".format(blue))\n        if opacity is not None: args.append(\"--opacity='{}'\".format(opacity))\n        args.append(\"--output='{}'\".format(output))\n        if enhance: args.append(\"--enhance\")\n        if zeros: args.append(\"--zeros\")\n        return self.run_tool('create_colour_composite', args, callback) # returns 1 if error\n\n    def flip_image(self, i, output, direction=\"vertical\", callback=None):\n        \"\"\"Reflects an image in the vertical or horizontal axis.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        direction -- Direction of reflection; options include 'v' (vertical), 'h' (horizontal), and 'b' (both). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--direction={}\".format(direction))\n        return self.run_tool('flip_image', args, callback) # returns 1 if error\n\n    def ihs_to_rgb(self, intensity, hue, saturation, red=None, green=None, blue=None, output=None, callback=None):\n        \"\"\"Converts intensity, hue, and saturation (IHS) images into red, green, and blue (RGB) images.\n\n        Keyword arguments:\n\n        intensity -- Input intensity file. \n        hue -- Input hue file. \n        saturation -- Input saturation file. \n        red -- Output red band file. Optionally specified if colour-composite not specified. \n        green -- Output green band file. Optionally specified if colour-composite not specified. \n        blue -- Output blue band file. Optionally specified if colour-composite not specified. \n        output -- Output colour-composite file. Only used if individual bands are not specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--intensity='{}'\".format(intensity))\n        args.append(\"--hue='{}'\".format(hue))\n        args.append(\"--saturation='{}'\".format(saturation))\n        if red is not None: args.append(\"--red='{}'\".format(red))\n        if green is not None: args.append(\"--green='{}'\".format(green))\n        if blue is not None: args.append(\"--blue='{}'\".format(blue))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        return self.run_tool('ihs_to_rgb', args, callback) # returns 1 if error\n\n    def image_slider(self, input1, input2, output, palette1=\"grey\", reverse1=False, label1=\"\", palette2=\"grey\", reverse2=False, label2=\"\", height=600, callback=None):\n        \"\"\"This tool creates an image slider from two input images.\n\n        Keyword arguments:\n\n        input1 -- Name of the left input image file. \n        palette1 -- Left image palette; options are 'grey', 'atlas', 'high_relief', 'arid', 'soft', 'muted', 'purple', 'viridi', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep', and 'rgb'. \n        reverse1 -- Reverse left image palette?. \n        label1 -- Left image label (leave blank for none). \n        input2 -- Name of the right input image file. \n        palette2 -- Right image palette; options are 'grey', 'atlas', 'high_relief', 'arid', 'soft', 'muted', 'purple', 'viridi', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep', and 'rgb'. \n        reverse2 -- Reverse right image palette?. \n        label2 -- Right image label (leave blank for none). \n        output -- Name of the output HTML file (*.html). \n        height -- Image height, in pixels. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--palette1={}\".format(palette1))\n        if reverse1: args.append(\"--reverse1\")\n        args.append(\"--label1={}\".format(label1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--palette2={}\".format(palette2))\n        if reverse2: args.append(\"--reverse2\")\n        args.append(\"--label2={}\".format(label2))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--height={}\".format(height))\n        return self.run_tool('image_slider', args, callback) # returns 1 if error\n\n    def image_stack_profile(self, inputs, points, output, callback=None):\n        \"\"\"Plots an image stack profile (i.e. signature) for a set of points and multispectral images.\n\n        Keyword arguments:\n\n        inputs -- Input multispectral image files. \n        points -- Input vector points file. \n        output -- Output HTML file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--points='{}'\".format(points))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('image_stack_profile', args, callback) # returns 1 if error\n\n    def integral_image(self, i, output, callback=None):\n        \"\"\"Transforms an input image (summed area table) into its integral image equivalent.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('integral_image', args, callback) # returns 1 if error\n\n    def line_thinning(self, i, output, callback=None):\n        \"\"\"Performs line thinning a on Boolean raster image; intended to be used with the RemoveSpurs tool.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('line_thinning', args, callback) # returns 1 if error\n\n    def mosaic(self, output, inputs=None, method=\"nn\", callback=None):\n        \"\"\"Mosaics two or more images together.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        method -- Resampling method; options include 'nn' (nearest neighbour), 'bilinear', and 'cc' (cubic convolution). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if inputs is not None: args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--method={}\".format(method))\n        return self.run_tool('mosaic', args, callback) # returns 1 if error\n\n    def mosaic_with_feathering(self, input1, input2, output, method=\"cc\", weight=4.0, callback=None):\n        \"\"\"Mosaics two images together using a feathering technique in overlapping areas to reduce edge-effects.\n\n        Keyword arguments:\n\n        input1 -- Input raster file to modify. \n        input2 -- Input reference raster file. \n        output -- Output raster file. \n        method -- Resampling method; options include 'nn' (nearest neighbour), 'bilinear', and 'cc' (cubic convolution). \n        weight -- . \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--method={}\".format(method))\n        args.append(\"--weight={}\".format(weight))\n        return self.run_tool('mosaic_with_feathering', args, callback) # returns 1 if error\n\n    def normalized_difference_index(self, input1, input2, output, clip=0.0, correction=0.0, callback=None):\n        \"\"\"Calculate a normalized-difference index (NDI) from two bands of multispectral image data.\n\n        Keyword arguments:\n\n        input1 -- Input image 1 (e.g. near-infrared band). \n        input2 -- Input image 2 (e.g. red band). \n        output -- Output raster file. \n        clip -- Optional amount to clip the distribution tails by, in percent. \n        correction -- Optional adjustment value (e.g. 1, or 0.16 for the optimal soil adjusted vegetation index, OSAVI). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--clip={}\".format(clip))\n        args.append(\"--correction={}\".format(correction))\n        return self.run_tool('normalized_difference_index', args, callback) # returns 1 if error\n\n    def opening(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"An opening is a mathematical morphology operation involving a dilation (max filter) of an erosion (min filter) set.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('opening', args, callback) # returns 1 if error\n\n    def remove_spurs(self, i, output, iterations=10, callback=None):\n        \"\"\"Removes the spurs (pruning operation) from a Boolean line image; intended to be used on the output of the LineThinning tool.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        iterations -- Maximum number of iterations. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--iterations={}\".format(iterations))\n        return self.run_tool('remove_spurs', args, callback) # returns 1 if error\n\n    def resample(self, inputs, output, cell_size=None, base=None, method=\"cc\", callback=None):\n        \"\"\"Resamples one or more input images into a destination image.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        base -- Optionally specified input base raster file. Not used when a cell size is specified. \n        method -- Resampling method; options include 'nn' (nearest neighbour), 'bilinear', and 'cc' (cubic convolution). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        if cell_size is not None: args.append(\"--cell_size='{}'\".format(cell_size))\n        if base is not None: args.append(\"--base='{}'\".format(base))\n        args.append(\"--method={}\".format(method))\n        return self.run_tool('resample', args, callback) # returns 1 if error\n\n    def rgb_to_ihs(self, intensity, hue, saturation, red=None, green=None, blue=None, composite=None, callback=None):\n        \"\"\"Converts red, green, and blue (RGB) images into intensity, hue, and saturation (IHS) images.\n\n        Keyword arguments:\n\n        red -- Input red band image file. Optionally specified if colour-composite not specified. \n        green -- Input green band image file. Optionally specified if colour-composite not specified. \n        blue -- Input blue band image file. Optionally specified if colour-composite not specified. \n        composite -- Input colour-composite image file. Only used if individual bands are not specified. \n        intensity -- Output intensity raster file. \n        hue -- Output hue raster file. \n        saturation -- Output saturation raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if red is not None: args.append(\"--red='{}'\".format(red))\n        if green is not None: args.append(\"--green='{}'\".format(green))\n        if blue is not None: args.append(\"--blue='{}'\".format(blue))\n        if composite is not None: args.append(\"--composite='{}'\".format(composite))\n        args.append(\"--intensity='{}'\".format(intensity))\n        args.append(\"--hue='{}'\".format(hue))\n        args.append(\"--saturation='{}'\".format(saturation))\n        return self.run_tool('rgb_to_ihs', args, callback) # returns 1 if error\n\n    def split_colour_composite(self, i, red=None, green=None, blue=None, callback=None):\n        \"\"\"Splits an RGB colour composite image into separate multispectral images.\n\n        Keyword arguments:\n\n        i -- Input colour composite image file. \n        red -- Output red band file. \n        green -- Output green band file. \n        blue -- Output blue band file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if red is not None: args.append(\"--red='{}'\".format(red))\n        if green is not None: args.append(\"--green='{}'\".format(green))\n        if blue is not None: args.append(\"--blue='{}'\".format(blue))\n        return self.run_tool('split_colour_composite', args, callback) # returns 1 if error\n\n    def thicken_raster_line(self, i, output, callback=None):\n        \"\"\"Thickens single-cell wide lines within a raster image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('thicken_raster_line', args, callback) # returns 1 if error\n\n    def tophat_transform(self, i, output, filterx=11, filtery=11, variant=\"white\", callback=None):\n        \"\"\"Performs either a white or black top-hat transform on an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        variant -- Optional variant value. Options include 'white' and 'black'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        args.append(\"--variant={}\".format(variant))\n        return self.run_tool('tophat_transform', args, callback) # returns 1 if error\n\n    def write_function_memory_insertion(self, input1, input2, output, input3=None, callback=None):\n        \"\"\"Performs a write function memory insertion for single-band multi-date change detection.\n\n        Keyword arguments:\n\n        input1 -- Input raster file associated with the first date. \n        input2 -- Input raster file associated with the second date. \n        input3 -- Optional input raster file associated with the third date. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        if input3 is not None: args.append(\"--input3='{}'\".format(input3))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('write_function_memory_insertion', args, callback) # returns 1 if error\n\n    #########################################\n    # Image Processing Tools/Classification #\n    #########################################\n\n    def evaluate_training_sites(self, inputs, polys, field, output, callback=None):\n        \"\"\"This tool can be used to inspect the overlap in spectral signatures of training sites for various classes.\n\n        Keyword arguments:\n\n        inputs -- Name of the input band images. \n        polys -- Name of the input training site polygons shapefile. \n        field -- Name of the attribute containing class name data. \n        output -- Name of the output report file (*.html). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--polys='{}'\".format(polys))\n        args.append(\"--field='{}'\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('evaluate_training_sites', args, callback) # returns 1 if error\n\n    def generalize_classified_raster(self, i, output, min_size=4, method=\"longest\", callback=None):\n        \"\"\"Generalizes a raster containing class or object features by removing small features.\n\n        Keyword arguments:\n\n        i -- Name of the input raster image file. \n        output -- Name of the output raster file. \n        min_size -- Minimum feature size, in grid cells. \n        method -- Grouping method; one of 'longest' (default), 'largest', and 'nearest'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--min_size={}\".format(min_size))\n        args.append(\"--method={}\".format(method))\n        return self.run_tool('generalize_classified_raster', args, callback) # returns 1 if error\n\n    def generalize_with_similarity(self, i, similarity, output, min_size=4, callback=None):\n        \"\"\"Generalizes a raster containing class or object features by removing small features using similarity criteria of neighbouring features.\n\n        Keyword arguments:\n\n        i -- Name of the input raster image file. \n        similarity -- Names of the input similarity images. \n        output -- Name of the output raster file. \n        min_size -- Minimum feature size, in grid cells. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--similarity='{}'\".format(similarity))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--min_size={}\".format(min_size))\n        return self.run_tool('generalize_with_similarity', args, callback) # returns 1 if error\n\n    def image_segmentation(self, inputs, output, threshold=0.5, steps=10, min_area=4, callback=None):\n        \"\"\"Performs a region-growing based segmentation on a set of multi-spectral images.\n\n        Keyword arguments:\n\n        inputs -- Names of the input band images. \n        output -- Name of the output raster file. \n        threshold -- Distance threshold, in z-scores. \n        steps -- Number of steps. \n        min_area -- Minimum object area, in grid cells (1-8). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--threshold={}\".format(threshold))\n        args.append(\"--steps={}\".format(steps))\n        args.append(\"--min_area={}\".format(min_area))\n        return self.run_tool('image_segmentation', args, callback) # returns 1 if error\n\n    def min_dist_classification(self, inputs, polys, field, output, threshold=None, callback=None):\n        \"\"\"Performs a supervised minimum-distance classification using training site polygons and multi-spectral images.\n\n        Keyword arguments:\n\n        inputs -- Names of the input band images. \n        polys -- Name of the input training site polygons shapefile. \n        field -- Name of the attribute containing class name data. \n        output -- Name of the output raster file. \n        threshold -- Distance threshold, in z-scores; blank for none. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--polys='{}'\".format(polys))\n        args.append(\"--field='{}'\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        if threshold is not None: args.append(\"--threshold='{}'\".format(threshold))\n        return self.run_tool('min_dist_classification', args, callback) # returns 1 if error\n\n    def parallelepiped_classification(self, inputs, polys, field, output, callback=None):\n        \"\"\"Performs a supervised parallelepiped classification using training site polygons and multi-spectral images.\n\n        Keyword arguments:\n\n        inputs -- Name of the input band images. \n        polys -- Name of the input training site polygons shapefile. \n        field -- Name of the attribute containing class name data. \n        output -- Name of the output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--polys='{}'\".format(polys))\n        args.append(\"--field='{}'\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('parallelepiped_classification', args, callback) # returns 1 if error\n\n    ##################################\n    # Image Processing Tools/Filters #\n    ##################################\n\n    def adaptive_filter(self, i, output, filterx=11, filtery=11, threshold=2.0, callback=None):\n        \"\"\"Performs an adaptive filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        threshold -- Difference from mean threshold, in standard deviations. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        args.append(\"--threshold={}\".format(threshold))\n        return self.run_tool('adaptive_filter', args, callback) # returns 1 if error\n\n    def bilateral_filter(self, i, output, sigma_dist=0.75, sigma_int=1.0, callback=None):\n        \"\"\"A bilateral filter is an edge-preserving smoothing filter introduced by Tomasi and Manduchi (1998).\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        sigma_dist -- Standard deviation in distance in pixels. \n        sigma_int -- Standard deviation in intensity in pixels. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--sigma_dist={}\".format(sigma_dist))\n        args.append(\"--sigma_int={}\".format(sigma_int))\n        return self.run_tool('bilateral_filter', args, callback) # returns 1 if error\n\n    def canny_edge_detection(self, i, output, sigma=0.5, low=0.05, high=0.15, add_back=False, callback=None):\n        \"\"\"This tool performs a Canny edge-detection filter on an input image.\n\n        Keyword arguments:\n\n        i -- Name of the input raster image file. \n        output -- Name of the output raster image file. \n        sigma -- Sigma value used in Gaussian filtering, default = 0.5. \n        low -- Low threshold, default = 0.05. \n        high -- High threshold, default = 0.15. \n        add_back -- Add the edge cells back to the input image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--sigma={}\".format(sigma))\n        args.append(\"--low={}\".format(low))\n        args.append(\"--high={}\".format(high))\n        if add_back: args.append(\"--add_back\")\n        return self.run_tool('canny_edge_detection', args, callback) # returns 1 if error\n\n    def conservative_smoothing_filter(self, i, output, filterx=3, filtery=3, callback=None):\n        \"\"\"Performs a conservative-smoothing filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('conservative_smoothing_filter', args, callback) # returns 1 if error\n\n    def corner_detection(self, i, output, callback=None):\n        \"\"\"Identifies corner patterns in boolean images using hit-and-miss pattern matching.\n\n        Keyword arguments:\n\n        i -- Input boolean image. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('corner_detection', args, callback) # returns 1 if error\n\n    def diff_of_gaussian_filter(self, i, output, sigma1=2.0, sigma2=4.0, callback=None):\n        \"\"\"Performs a Difference of Gaussian (DoG) filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        sigma1 -- Standard deviation distance in pixels. \n        sigma2 -- Standard deviation distance in pixels. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--sigma1={}\".format(sigma1))\n        args.append(\"--sigma2={}\".format(sigma2))\n        return self.run_tool('diff_of_gaussian_filter', args, callback) # returns 1 if error\n\n    def diversity_filter(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Assigns each cell in the output grid the number of different values in a moving window centred on each grid cell in the input raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('diversity_filter', args, callback) # returns 1 if error\n\n    def edge_preserving_mean_filter(self, i, output, threshold, filter=11, callback=None):\n        \"\"\"Performs a simple edge-preserving mean filter on an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filter -- Size of the filter kernel. \n        threshold -- Maximum difference in values. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filter={}\".format(filter))\n        args.append(\"--threshold='{}'\".format(threshold))\n        return self.run_tool('edge_preserving_mean_filter', args, callback) # returns 1 if error\n\n    def emboss_filter(self, i, output, direction=\"n\", clip=0.0, callback=None):\n        \"\"\"Performs an emboss filter on an image, similar to a hillshade operation.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        direction -- Direction of reflection; options include 'n', 's', 'e', 'w', 'ne', 'se', 'nw', 'sw'. \n        clip -- Optional amount to clip the distribution tails by, in percent. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--direction={}\".format(direction))\n        args.append(\"--clip={}\".format(clip))\n        return self.run_tool('emboss_filter', args, callback) # returns 1 if error\n\n    def fast_almost_gaussian_filter(self, i, output, sigma=1.8, callback=None):\n        \"\"\"Performs a fast approximate Gaussian filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        sigma -- Standard deviation distance in pixels. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--sigma={}\".format(sigma))\n        return self.run_tool('fast_almost_gaussian_filter', args, callback) # returns 1 if error\n\n    def gaussian_filter(self, i, output, sigma=0.75, callback=None):\n        \"\"\"Performs a Gaussian filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        sigma -- Standard deviation distance in pixels. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--sigma={}\".format(sigma))\n        return self.run_tool('gaussian_filter', args, callback) # returns 1 if error\n\n    def high_pass_bilateral_filter(self, i, output, sigma_dist=0.75, sigma_int=1.0, callback=None):\n        \"\"\"Performs a high-pass bilateral filter, by differencing an input image by the bilateral filter by Tomasi and Manduchi (1998).\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        sigma_dist -- Standard deviation in distance in pixels. \n        sigma_int -- Standard deviation in intensity in pixels. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--sigma_dist={}\".format(sigma_dist))\n        args.append(\"--sigma_int={}\".format(sigma_int))\n        return self.run_tool('high_pass_bilateral_filter', args, callback) # returns 1 if error\n\n    def high_pass_filter(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Performs a high-pass filter on an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('high_pass_filter', args, callback) # returns 1 if error\n\n    def high_pass_median_filter(self, i, output, filterx=11, filtery=11, sig_digits=2, callback=None):\n        \"\"\"Performs a high pass median filter on an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        sig_digits -- Number of significant digits. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        args.append(\"--sig_digits={}\".format(sig_digits))\n        return self.run_tool('high_pass_median_filter', args, callback) # returns 1 if error\n\n    def k_nearest_mean_filter(self, i, output, filterx=11, filtery=11, k=5, callback=None):\n        \"\"\"A k-nearest mean filter is a type of edge-preserving smoothing filter.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        k -- k-value in pixels; this is the number of nearest-valued neighbours to use. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        args.append(\"-k={}\".format(k))\n        return self.run_tool('k_nearest_mean_filter', args, callback) # returns 1 if error\n\n    def laplacian_filter(self, i, output, variant=\"3x3(1)\", clip=0.0, callback=None):\n        \"\"\"Performs a Laplacian filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        variant -- Optional variant value. Options include 3x3(1), 3x3(2), 3x3(3), 3x3(4), 5x5(1), and 5x5(2) (default is 3x3(1)). \n        clip -- Optional amount to clip the distribution tails by, in percent. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--variant={}\".format(variant))\n        args.append(\"--clip={}\".format(clip))\n        return self.run_tool('laplacian_filter', args, callback) # returns 1 if error\n\n    def laplacian_of_gaussian_filter(self, i, output, sigma=0.75, callback=None):\n        \"\"\"Performs a Laplacian-of-Gaussian (LoG) filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        sigma -- Standard deviation in pixels. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--sigma={}\".format(sigma))\n        return self.run_tool('laplacian_of_gaussian_filter', args, callback) # returns 1 if error\n\n    def lee_sigma_filter(self, i, output, filterx=11, filtery=11, sigma=10.0, m=5.0, callback=None):\n        \"\"\"Performs a Lee (Sigma) smoothing filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        sigma -- Sigma value should be related to the standard deviation of the distribution of image speckle noise. \n        m -- M-threshold value the minimum allowable number of pixels within the intensity range. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        args.append(\"--sigma={}\".format(sigma))\n        args.append(\"-m={}\".format(m))\n        return self.run_tool('lee_sigma_filter', args, callback) # returns 1 if error\n\n    def line_detection_filter(self, i, output, variant=\"vertical\", absvals=False, clip=0.0, callback=None):\n        \"\"\"Performs a line-detection filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        variant -- Optional variant value. Options include 'v' (vertical), 'h' (horizontal), '45', and '135' (default is 'v'). \n        absvals -- Optional flag indicating whether outputs should be absolute values. \n        clip -- Optional amount to clip the distribution tails by, in percent. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--variant={}\".format(variant))\n        if absvals: args.append(\"--absvals\")\n        args.append(\"--clip={}\".format(clip))\n        return self.run_tool('line_detection_filter', args, callback) # returns 1 if error\n\n    def majority_filter(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Assigns each cell in the output grid the most frequently occurring value (mode) in a moving window centred on each grid cell in the input raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('majority_filter', args, callback) # returns 1 if error\n\n    def maximum_filter(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Assigns each cell in the output grid the maximum value in a moving window centred on each grid cell in the input raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('maximum_filter', args, callback) # returns 1 if error\n\n    def mean_filter(self, i, output, filterx=3, filtery=3, callback=None):\n        \"\"\"Performs a mean filter (low-pass filter) on an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('mean_filter', args, callback) # returns 1 if error\n\n    def median_filter(self, i, output, filterx=11, filtery=11, sig_digits=2, callback=None):\n        \"\"\"Performs a median filter on an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        sig_digits -- Number of significant digits. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        args.append(\"--sig_digits={}\".format(sig_digits))\n        return self.run_tool('median_filter', args, callback) # returns 1 if error\n\n    def minimum_filter(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Assigns each cell in the output grid the minimum value in a moving window centred on each grid cell in the input raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('minimum_filter', args, callback) # returns 1 if error\n\n    def olympic_filter(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Performs an olympic smoothing filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('olympic_filter', args, callback) # returns 1 if error\n\n    def percentile_filter(self, i, output, filterx=11, filtery=11, sig_digits=2, callback=None):\n        \"\"\"Performs a percentile filter on an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        sig_digits -- Number of significant digits. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        args.append(\"--sig_digits={}\".format(sig_digits))\n        return self.run_tool('percentile_filter', args, callback) # returns 1 if error\n\n    def prewitt_filter(self, i, output, clip=0.0, callback=None):\n        \"\"\"Performs a Prewitt edge-detection filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        clip -- Optional amount to clip the distribution tails by, in percent. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--clip={}\".format(clip))\n        return self.run_tool('prewitt_filter', args, callback) # returns 1 if error\n\n    def range_filter(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Assigns each cell in the output grid the range of values in a moving window centred on each grid cell in the input raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('range_filter', args, callback) # returns 1 if error\n\n    def roberts_cross_filter(self, i, output, clip=0.0, callback=None):\n        \"\"\"Performs a Robert's cross edge-detection filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        clip -- Optional amount to clip the distribution tails by, in percent. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--clip={}\".format(clip))\n        return self.run_tool('roberts_cross_filter', args, callback) # returns 1 if error\n\n    def scharr_filter(self, i, output, clip=0.0, callback=None):\n        \"\"\"Performs a Scharr edge-detection filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        clip -- Optional amount to clip the distribution tails by, in percent. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--clip={}\".format(clip))\n        return self.run_tool('scharr_filter', args, callback) # returns 1 if error\n\n    def sobel_filter(self, i, output, variant=\"3x3\", clip=0.0, callback=None):\n        \"\"\"Performs a Sobel edge-detection filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        variant -- Optional variant value. Options include 3x3 and 5x5 (default is 3x3). \n        clip -- Optional amount to clip the distribution tails by, in percent (default is 0.0). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--variant={}\".format(variant))\n        args.append(\"--clip={}\".format(clip))\n        return self.run_tool('sobel_filter', args, callback) # returns 1 if error\n\n    def standard_deviation_filter(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Assigns each cell in the output grid the standard deviation of values in a moving window centred on each grid cell in the input raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('standard_deviation_filter', args, callback) # returns 1 if error\n\n    def total_filter(self, i, output, filterx=11, filtery=11, callback=None):\n        \"\"\"Performs a total filter on an input image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        filterx -- Size of the filter kernel in the x-direction. \n        filtery -- Size of the filter kernel in the y-direction. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--filterx={}\".format(filterx))\n        args.append(\"--filtery={}\".format(filtery))\n        return self.run_tool('total_filter', args, callback) # returns 1 if error\n\n    def unsharp_masking(self, i, output, sigma=0.75, amount=100.0, threshold=0.0, callback=None):\n        \"\"\"An image sharpening technique that enhances edges.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        sigma -- Standard deviation distance in pixels. \n        amount -- A percentage and controls the magnitude of each overshoot. \n        threshold -- Controls the minimal brightness change that will be sharpened. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--sigma={}\".format(sigma))\n        args.append(\"--amount={}\".format(amount))\n        args.append(\"--threshold={}\".format(threshold))\n        return self.run_tool('unsharp_masking', args, callback) # returns 1 if error\n\n    def user_defined_weights_filter(self, i, weights, output, center=\"center\", normalize=False, callback=None):\n        \"\"\"Performs a user-defined weights filter on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        weights -- Input weights file. \n        output -- Output raster file. \n        center -- Kernel center cell; options include 'center', 'upper-left', 'upper-right', 'lower-left', 'lower-right'. \n        normalize -- Normalize kernel weights? This can reduce edge effects and lessen the impact of data gaps (nodata) but is not suited when the kernel weights sum to zero. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--weights='{}'\".format(weights))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--center={}\".format(center))\n        if normalize: args.append(\"--normalize\")\n        return self.run_tool('user_defined_weights_filter', args, callback) # returns 1 if error\n\n    ############################################\n    # Image Processing Tools/Image Enhancement #\n    ############################################\n\n    def balance_contrast_enhancement(self, i, output, band_mean=100.0, callback=None):\n        \"\"\"Performs a balance contrast enhancement on a colour-composite image of multispectral data.\n\n        Keyword arguments:\n\n        i -- Input colour composite image file. \n        output -- Output raster file. \n        band_mean -- Band mean value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--band_mean={}\".format(band_mean))\n        return self.run_tool('balance_contrast_enhancement', args, callback) # returns 1 if error\n\n    def correct_vignetting(self, i, pp, output, focal_length=304.8, image_width=228.6, n=4.0, callback=None):\n        \"\"\"Corrects the darkening of images towards corners.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        pp -- Input principal point file. \n        output -- Output raster file. \n        focal_length -- Camera focal length, in millimeters. \n        image_width -- Distance between photograph edges, in millimeters. \n        n -- The 'n' parameter. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--pp='{}'\".format(pp))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--focal_length={}\".format(focal_length))\n        args.append(\"--image_width={}\".format(image_width))\n        args.append(\"-n={}\".format(n))\n        return self.run_tool('correct_vignetting', args, callback) # returns 1 if error\n\n    def direct_decorrelation_stretch(self, i, output, k=0.5, clip=1.0, callback=None):\n        \"\"\"Performs a direct decorrelation stretch enhancement on a colour-composite image of multispectral data.\n\n        Keyword arguments:\n\n        i -- Input colour composite image file. \n        output -- Output raster file. \n        k -- Achromatic factor (k) ranges between 0 (no effect) and 1 (full saturation stretch), although typical values range from 0.3 to 0.7. \n        clip -- Optional percent to clip the upper tail by during the stretch. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"-k={}\".format(k))\n        args.append(\"--clip={}\".format(clip))\n        return self.run_tool('direct_decorrelation_stretch', args, callback) # returns 1 if error\n\n    def gamma_correction(self, i, output, gamma=0.5, callback=None):\n        \"\"\"Performs a gamma correction on an input images.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        gamma -- Gamma value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--gamma={}\".format(gamma))\n        return self.run_tool('gamma_correction', args, callback) # returns 1 if error\n\n    def gaussian_contrast_stretch(self, i, output, num_tones=256, callback=None):\n        \"\"\"Performs a Gaussian contrast stretch on input images.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        num_tones -- Number of tones in the output image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--num_tones={}\".format(num_tones))\n        return self.run_tool('gaussian_contrast_stretch', args, callback) # returns 1 if error\n\n    def histogram_equalization(self, i, output, num_tones=256, callback=None):\n        \"\"\"Performs a histogram equalization contrast enhancement on an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        num_tones -- Number of tones in the output image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--num_tones={}\".format(num_tones))\n        return self.run_tool('histogram_equalization', args, callback) # returns 1 if error\n\n    def histogram_matching(self, i, histo_file, output, callback=None):\n        \"\"\"Alters the statistical distribution of a raster image matching it to a specified PDF.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        histo_file -- Input reference probability distribution function (pdf) text file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--histo_file='{}'\".format(histo_file))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('histogram_matching', args, callback) # returns 1 if error\n\n    def histogram_matching_two_images(self, input1, input2, output, callback=None):\n        \"\"\"Alters the cumulative distribution function of a raster image to that of another image.\n\n        Keyword arguments:\n\n        input1 -- Input raster file to modify. \n        input2 -- Input reference raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('histogram_matching_two_images', args, callback) # returns 1 if error\n\n    def min_max_contrast_stretch(self, i, output, min_val, max_val, num_tones=256, callback=None):\n        \"\"\"Performs a min-max contrast stretch on an input greytone image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        min_val -- Lower tail clip value. \n        max_val -- Upper tail clip value. \n        num_tones -- Number of tones in the output image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--min_val='{}'\".format(min_val))\n        args.append(\"--max_val='{}'\".format(max_val))\n        args.append(\"--num_tones={}\".format(num_tones))\n        return self.run_tool('min_max_contrast_stretch', args, callback) # returns 1 if error\n\n    def panchromatic_sharpening(self, pan, output, red=None, green=None, blue=None, composite=None, method=\"brovey\", callback=None):\n        \"\"\"Increases the spatial resolution of image data by combining multispectral bands with panchromatic data.\n\n        Keyword arguments:\n\n        red -- Input red band image file. Optionally specified if colour-composite not specified. \n        green -- Input green band image file. Optionally specified if colour-composite not specified. \n        blue -- Input blue band image file. Optionally specified if colour-composite not specified. \n        composite -- Input colour-composite image file. Only used if individual bands are not specified. \n        pan -- Input panchromatic band file. \n        output -- Output colour composite file. \n        method -- Options include 'brovey' (default) and 'ihs'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if red is not None: args.append(\"--red='{}'\".format(red))\n        if green is not None: args.append(\"--green='{}'\".format(green))\n        if blue is not None: args.append(\"--blue='{}'\".format(blue))\n        if composite is not None: args.append(\"--composite='{}'\".format(composite))\n        args.append(\"--pan='{}'\".format(pan))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--method={}\".format(method))\n        return self.run_tool('panchromatic_sharpening', args, callback) # returns 1 if error\n\n    def percentage_contrast_stretch(self, i, output, clip=1.0, tail=\"both\", num_tones=256, callback=None):\n        \"\"\"Performs a percentage linear contrast stretch on input images.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        clip -- Optional amount to clip the distribution tails by, in percent. \n        tail -- Specified which tails to clip; options include 'upper', 'lower', and 'both' (default is 'both'). \n        num_tones -- Number of tones in the output image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--clip={}\".format(clip))\n        args.append(\"--tail={}\".format(tail))\n        args.append(\"--num_tones={}\".format(num_tones))\n        return self.run_tool('percentage_contrast_stretch', args, callback) # returns 1 if error\n\n    def piecewise_contrast_stretch(self, i, output, function=\"\", greytones=1024, callback=None):\n        \"\"\"Performs a piecewise contrast stretch on an input image.\n\n        Keyword arguments:\n\n        i -- Name of the input raster image file. \n        output -- Name of the output raster image file. \n        function -- Piecewise function break-points e.g. '(50, 0.1); (150, 0.8); (255; 1.0). \n        greytones -- Number of greytones in the output image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--function={}\".format(function))\n        args.append(\"--greytones={}\".format(greytones))\n        return self.run_tool('piecewise_contrast_stretch', args, callback) # returns 1 if error\n\n    def sigmoidal_contrast_stretch(self, i, output, cutoff=0.0, gain=1.0, num_tones=256, callback=None):\n        \"\"\"Performs a sigmoidal contrast stretch on input images.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        cutoff -- Cutoff value between 0.0 and 0.95. \n        gain -- Gain value. \n        num_tones -- Number of tones in the output image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--cutoff={}\".format(cutoff))\n        args.append(\"--gain={}\".format(gain))\n        args.append(\"--num_tones={}\".format(num_tones))\n        return self.run_tool('sigmoidal_contrast_stretch', args, callback) # returns 1 if error\n\n    def standard_deviation_contrast_stretch(self, i, output, stdev=2.0, num_tones=256, callback=None):\n        \"\"\"Performs a standard-deviation contrast stretch on input images.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        stdev -- Standard deviation clip value. \n        num_tones -- Number of tones in the output image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--stdev={}\".format(stdev))\n        args.append(\"--num_tones={}\".format(num_tones))\n        return self.run_tool('standard_deviation_contrast_stretch', args, callback) # returns 1 if error\n\n    ###############\n    # LiDAR Tools #\n    ###############\n\n    def ascii_to_las(self, inputs, pattern, proj=None, callback=None):\n        \"\"\"Converts one or more ASCII files containing LiDAR points into LAS files.\n\n        Keyword arguments:\n\n        inputs -- Input LiDAR  ASCII files (.csv). \n        pattern -- Input field pattern. \n        proj -- Well-known-text string or EPSG code describing projection. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--pattern='{}'\".format(pattern))\n        if proj is not None: args.append(\"--proj='{}'\".format(proj))\n        return self.run_tool('ascii_to_las', args, callback) # returns 1 if error\n\n    def classify_buildings_in_lidar(self, i, buildings, output, callback=None):\n        \"\"\"Reclassifies a LiDAR points that lie within vector building footprints.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        buildings -- Input vector polygons file. \n        output -- Output LiDAR file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--buildings='{}'\".format(buildings))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('classify_buildings_in_lidar', args, callback) # returns 1 if error\n\n    def classify_lidar(self, i=None, output=None, radius=1.5, grd_threshold=0.1, oto_threshold=2.0, planarity_threshold=0.85, linearity_threshold=0.70, iterations=30, facade_threshold=0.5, callback=None):\n        \"\"\"Classify points within a LiDAR point cloud based on point properties.\n\n        Keyword arguments:\n\n        i -- Name of the input LiDAR points. \n        output -- Name of the output LiDAR points. \n        radius -- Search distance used in neighbourhood search (metres). \n        grd_threshold -- Ground threshold (metres). \n        oto_threshold -- Off-terrain object threshold (metres). \n        planarity_threshold -- Planarity threshold (0-1). \n        linearity_threshold -- Linearity threshold (0-1). \n        iterations -- Number of iterations. \n        facade_threshold -- Facade threshold (metres). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--radius={}\".format(radius))\n        args.append(\"--grd_threshold={}\".format(grd_threshold))\n        args.append(\"--oto_threshold={}\".format(oto_threshold))\n        args.append(\"--planarity_threshold={}\".format(planarity_threshold))\n        args.append(\"--linearity_threshold={}\".format(linearity_threshold))\n        args.append(\"--iterations={}\".format(iterations))\n        args.append(\"--facade_threshold={}\".format(facade_threshold))\n        return self.run_tool('classify_lidar', args, callback) # returns 1 if error\n\n    def classify_overlap_points(self, i, output, resolution=2.0, criterion=\"max scan angle\", filter=False, callback=None):\n        \"\"\"Classifies or filters LAS points in regions of overlapping flight lines.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        resolution -- The size of the square area used to evaluate nearby points in the LiDAR data. \n        criterion -- Criterion used to identify overlapping points; options are 'max scan angle', 'not min point source ID', 'not min time', 'multiple point source IDs'. \n        filter -- Filter out points from overlapping flightlines? If false, overlaps will simply be classified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--resolution={}\".format(resolution))\n        args.append(\"--criterion={}\".format(criterion))\n        if filter: args.append(\"--filter\")\n        return self.run_tool('classify_overlap_points', args, callback) # returns 1 if error\n\n    def clip_lidar_to_polygon(self, i, polygons, output, callback=None):\n        \"\"\"Clips a LiDAR point cloud to a vector polygon or polygons.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        polygons -- Input vector polygons file. \n        output -- Output LiDAR file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--polygons='{}'\".format(polygons))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('clip_lidar_to_polygon', args, callback) # returns 1 if error\n\n    def colourize_based_on_class(self, i=None, output=None, intensity_blending=50.0, clr_str=\"\", use_unique_clrs_for_buildings=False, radius=\"\", callback=None):\n        \"\"\"Sets the RGB values of a LiDAR point cloud based on the point classification values.\n\n        Keyword arguments:\n\n        i -- Name of the input LiDAR points. \n        output -- Name of the output LiDAR points. \n        intensity_blending -- Intensity blending amount (0-100%). \n        clr_str -- Colour values, e.g. 2: (184, 167, 108); 5: #9ab86c. \n        use_unique_clrs_for_buildings -- Use unique colours for each building?. \n        radius -- Search distance used in neighbourhood search. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--intensity_blending={}\".format(intensity_blending))\n        args.append(\"--clr_str={}\".format(clr_str))\n        if use_unique_clrs_for_buildings: args.append(\"--use_unique_clrs_for_buildings\")\n        args.append(\"--radius={}\".format(radius))\n        return self.run_tool('colourize_based_on_class', args, callback) # returns 1 if error\n\n    def colourize_based_on_point_returns(self, i=None, output=None, intensity_blending=50.0, only=\"(230,214,170)\", first=\"(0,140,0)\", intermediate=\"(255,0,255)\", last=\"(0,0,255)\", callback=None):\n        \"\"\"Sets the RGB values of a LiDAR point cloud based on the point returns.\n\n        Keyword arguments:\n\n        i -- Name of the input LiDAR points. \n        output -- Name of the output LiDAR points. \n        intensity_blending -- Intensity blending amount (0-100%). \n        only -- Only return colour, e.g. (230,214,170), #e6d6aa, or 0xe6d6aa. \n        first -- First return colour, e.g. (230,214,170), #e6d6aa, or 0xe6d6aa. \n        intermediate -- Intermediate return colour, e.g. (230,214,170), #e6d6aa, or 0xe6d6aa. \n        last -- Last return colour, e.g. (230,214,170), #e6d6aa, or 0xe6d6aa. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--intensity_blending={}\".format(intensity_blending))\n        args.append(\"--only={}\".format(only))\n        args.append(\"--first={}\".format(first))\n        args.append(\"--intermediate={}\".format(intermediate))\n        args.append(\"--last={}\".format(last))\n        return self.run_tool('colourize_based_on_point_returns', args, callback) # returns 1 if error\n\n    def erase_polygon_from_lidar(self, i, polygons, output, callback=None):\n        \"\"\"Erases (cuts out) a vector polygon or polygons from a LiDAR point cloud.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        polygons -- Input vector polygons file. \n        output -- Output LiDAR file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--polygons='{}'\".format(polygons))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('erase_polygon_from_lidar', args, callback) # returns 1 if error\n\n    def filter_lidar(self, i=None, output=None, statement=\"\", callback=None):\n        \"\"\"Filters points within a LiDAR point cloud based on point properties.\n\n        Keyword arguments:\n\n        i -- Name of the input LiDAR points. \n        output -- Name of the output LiDAR points. \n        statement -- Filter statement e.g. x < 5000.0 && y > 100.0 && is_late && !is_noise. This statement must be a valid Rust statement. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--statement={}\".format(statement))\n        return self.run_tool('filter_lidar', args, callback) # returns 1 if error\n\n    def filter_lidar_classes(self, i, output, exclude_cls=None, callback=None):\n        \"\"\"Removes points in a LAS file with certain specified class values.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if exclude_cls is not None: args.append(\"--exclude_cls='{}'\".format(exclude_cls))\n        return self.run_tool('filter_lidar_classes', args, callback) # returns 1 if error\n\n    def filter_lidar_scan_angles(self, i, output, threshold, callback=None):\n        \"\"\"Removes points in a LAS file with scan angles greater than a threshold.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        threshold -- Scan angle threshold. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--threshold='{}'\".format(threshold))\n        return self.run_tool('filter_lidar_scan_angles', args, callback) # returns 1 if error\n\n    def find_flightline_edge_points(self, i, output, callback=None):\n        \"\"\"Identifies points along a flightline's edge in a LAS file.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('find_flightline_edge_points', args, callback) # returns 1 if error\n\n    def flightline_overlap(self, i=None, output=None, resolution=1.0, callback=None):\n        \"\"\"Reads a LiDAR (LAS) point file and outputs a raster containing the number of overlapping flight-lines in each grid cell.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output file. \n        resolution -- Output raster's grid resolution. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--resolution={}\".format(resolution))\n        return self.run_tool('flightline_overlap', args, callback) # returns 1 if error\n\n    def height_above_ground(self, i=None, output=None, callback=None):\n        \"\"\"Normalizes a LiDAR point cloud, providing the height above the nearest ground-classified point.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file (including extension). \n        output -- Output lidar file (including extension). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        return self.run_tool('height_above_ground', args, callback) # returns 1 if error\n\n    def individual_tree_detection(self, i=None, output=None, min_search_radius=1.0, min_height=0.0, max_search_radius=\"\", max_height=\"\", only_use_veg=False, callback=None):\n        \"\"\"Identifies points in a LiDAR point cloud that are associated with the tops of individual trees.\n\n        Keyword arguments:\n\n        i -- Name of the input LiDAR file. \n        output -- Name of the output vector points file. \n        min_search_radius -- Minimum search radius (m). \n        min_height -- Minimum height (m). \n        max_search_radius -- Maximum search radius (m). \n        max_height -- Maximum height (m). \n        only_use_veg -- Only use veg. class points?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--min_search_radius={}\".format(min_search_radius))\n        args.append(\"--min_height={}\".format(min_height))\n        args.append(\"--max_search_radius={}\".format(max_search_radius))\n        args.append(\"--max_height={}\".format(max_height))\n        if only_use_veg: args.append(\"--only_use_veg\")\n        return self.run_tool('individual_tree_detection', args, callback) # returns 1 if error\n\n    def las_to_ascii(self, inputs, callback=None):\n        \"\"\"Converts one or more LAS files into ASCII text files.\n\n        Keyword arguments:\n\n        inputs -- Input LiDAR files. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        return self.run_tool('las_to_ascii', args, callback) # returns 1 if error\n\n    def las_to_laz(self, i=None, output=None, callback=None):\n        \"\"\"This tool converts one or more LAS files into the LAZ format.\n\n        Keyword arguments:\n\n        i -- Name of the input LAS files (leave blank to use all LAS files in WorkingDirectory. \n        output -- Output LAZ file (including extension). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        return self.run_tool('las_to_laz', args, callback) # returns 1 if error\n\n    def las_to_multipoint_shapefile(self, i=None, callback=None):\n        \"\"\"Converts one or more LAS files into MultipointZ vector Shapefiles. When the input parameter is not specified, the tool grids all LAS files contained within the working directory.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        return self.run_tool('las_to_multipoint_shapefile', args, callback) # returns 1 if error\n\n    def las_to_shapefile(self, i=None, callback=None):\n        \"\"\"Converts one or more LAS files into a vector Shapefile of POINT ShapeType.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        return self.run_tool('las_to_shapefile', args, callback) # returns 1 if error\n\n    def las_to_zlidar(self, inputs=None, outdir=None, compress=\"brotli\", level=5, callback=None):\n        \"\"\"Converts one or more LAS files into the zlidar compressed LiDAR data format.\n\n        Keyword arguments:\n\n        inputs -- Input LAS files. \n        outdir -- Output directory into which zlidar files are created. If unspecified, it is assumed to be the same as the inputs. \n        compress -- Compression method, including 'brotli' and 'deflate'. \n        level -- Compression level (1-9). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if inputs is not None: args.append(\"--inputs='{}'\".format(inputs))\n        if outdir is not None: args.append(\"--outdir='{}'\".format(outdir))\n        args.append(\"--compress={}\".format(compress))\n        args.append(\"--level={}\".format(level))\n        return self.run_tool('las_to_zlidar', args, callback) # returns 1 if error\n\n    def laz_to_las(self, i=None, output=None, callback=None):\n        \"\"\"This tool converts one or more LAZ files into the LAS format.\n\n        Keyword arguments:\n\n        i -- Name of the input LAZ files (leave blank to use all LAZ files in WorkingDirectory. \n        output -- Output LAS file (including extension). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        return self.run_tool('laz_to_las', args, callback) # returns 1 if error\n\n    def lidar_block_maximum(self, i=None, output=None, resolution=1.0, callback=None):\n        \"\"\"Creates a block-maximum raster from an input LAS file. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output file. \n        resolution -- Output raster's grid resolution. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--resolution={}\".format(resolution))\n        return self.run_tool('lidar_block_maximum', args, callback) # returns 1 if error\n\n    def lidar_block_minimum(self, i=None, output=None, resolution=1.0, callback=None):\n        \"\"\"Creates a block-minimum raster from an input LAS file. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output file. \n        resolution -- Output raster's grid resolution. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--resolution={}\".format(resolution))\n        return self.run_tool('lidar_block_minimum', args, callback) # returns 1 if error\n\n    def lidar_classify_subset(self, base, subset, output, subset_class, nonsubset_class=None, callback=None):\n        \"\"\"Classifies the values in one LiDAR point cloud that correspond with points in a subset cloud.\n\n        Keyword arguments:\n\n        base -- Input base LiDAR file. \n        subset -- Input subset LiDAR file. \n        output -- Output LiDAR file. \n        subset_class -- Subset point class value (must be 0-18; see LAS specifications). \n        nonsubset_class -- Non-subset point class value (must be 0-18; see LAS specifications). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--base='{}'\".format(base))\n        args.append(\"--subset='{}'\".format(subset))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--subset_class='{}'\".format(subset_class))\n        if nonsubset_class is not None: args.append(\"--nonsubset_class='{}'\".format(nonsubset_class))\n        return self.run_tool('lidar_classify_subset', args, callback) # returns 1 if error\n\n    def lidar_colourize(self, in_lidar, in_image, output, callback=None):\n        \"\"\"Adds the red-green-blue colour fields of a LiDAR (LAS) file based on an input image.\n\n        Keyword arguments:\n\n        in_lidar -- Input LiDAR file. \n        in_image -- Input colour image file. \n        output -- Output LiDAR file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--in_lidar='{}'\".format(in_lidar))\n        args.append(\"--in_image='{}'\".format(in_image))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('lidar_colourize', args, callback) # returns 1 if error\n\n    def lidar_contour(self, i=None, output=None, interval=10.0, base=0.0, smooth=5, parameter=\"elevation\", returns=\"all\", exclude_cls=None, minz=None, maxz=None, max_triangle_edge_length=None, callback=None):\n        \"\"\"This tool creates a vector contour coverage from an input LiDAR point file.\n\n        Keyword arguments:\n\n        i -- Name of the input LiDAR points. \n        output -- Name of the output vector lines file. \n        interval -- Contour interval. \n        base -- Base contour. \n        smooth -- Smoothing filter size (in num. points), e.g. 3, 5, 7, 9, 11. \n        parameter -- Interpolation parameter; options are 'elevation' (default), 'intensity', 'user_data'. \n        returns -- Point return types to include; options are 'all' (default), 'last', 'first'. \n        exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. \n        minz -- Optional minimum elevation for inclusion in interpolation. \n        maxz -- Optional maximum elevation for inclusion in interpolation. \n        max_triangle_edge_length -- Optional maximum triangle edge length; triangles larger than this size will not be gridded. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--interval={}\".format(interval))\n        args.append(\"--base={}\".format(base))\n        args.append(\"--smooth={}\".format(smooth))\n        args.append(\"--parameter={}\".format(parameter))\n        args.append(\"--returns={}\".format(returns))\n        if exclude_cls is not None: args.append(\"--exclude_cls='{}'\".format(exclude_cls))\n        if minz is not None: args.append(\"--minz='{}'\".format(minz))\n        if maxz is not None: args.append(\"--maxz='{}'\".format(maxz))\n        if max_triangle_edge_length is not None: args.append(\"--max_triangle_edge_length='{}'\".format(max_triangle_edge_length))\n        return self.run_tool('lidar_contour', args, callback) # returns 1 if error\n\n    def lidar_digital_surface_model(self, i=None, output=None, resolution=1.0, radius=0.5, minz=None, maxz=None, max_triangle_edge_length=None, callback=None):\n        \"\"\"Creates a top-surface digital surface model (DSM) from a LiDAR point cloud.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file (including extension). \n        output -- Output raster file (including extension). \n        resolution -- Output raster's grid resolution. \n        radius -- Search Radius. \n        minz -- Optional minimum elevation for inclusion in interpolation. \n        maxz -- Optional maximum elevation for inclusion in interpolation. \n        max_triangle_edge_length -- Optional maximum triangle edge length; triangles larger than this size will not be gridded. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--resolution={}\".format(resolution))\n        args.append(\"--radius={}\".format(radius))\n        if minz is not None: args.append(\"--minz='{}'\".format(minz))\n        if maxz is not None: args.append(\"--maxz='{}'\".format(maxz))\n        if max_triangle_edge_length is not None: args.append(\"--max_triangle_edge_length='{}'\".format(max_triangle_edge_length))\n        return self.run_tool('lidar_digital_surface_model', args, callback) # returns 1 if error\n\n    def lidar_eigenvalue_features(self, i=None, num_neighbours=None, radius=None, callback=None):\n        \"\"\"Calculate eigenvalue-based metrics from a LiDAR point cloud.\n\n        Keyword arguments:\n\n        i -- Name of the input LiDAR points. \n        num_neighbours -- Number of neighbours used in search. \n        radius -- Search distance used in neighbourhood search. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if num_neighbours is not None: args.append(\"--num_neighbours='{}'\".format(num_neighbours))\n        if radius is not None: args.append(\"--radius='{}'\".format(radius))\n        return self.run_tool('lidar_eigenvalue_features', args, callback) # returns 1 if error\n\n    def lidar_elevation_slice(self, i, output, minz=None, maxz=None, cls=False, inclassval=2, outclassval=1, callback=None):\n        \"\"\"Outputs all of the points within a LiDAR (LAS) point file that lie between a specified elevation range.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        minz -- Minimum elevation value (optional). \n        maxz -- Maximum elevation value (optional). \n        cls -- Optional boolean flag indicating whether points outside the range should be retained in output but reclassified. \n        inclassval -- Optional parameter specifying the class value assigned to points within the slice. \n        outclassval -- Optional parameter specifying the class value assigned to points within the slice. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if minz is not None: args.append(\"--minz='{}'\".format(minz))\n        if maxz is not None: args.append(\"--maxz='{}'\".format(maxz))\n        if cls: args.append(\"--class\")\n        args.append(\"--inclassval={}\".format(inclassval))\n        args.append(\"--outclassval={}\".format(outclassval))\n        return self.run_tool('lidar_elevation_slice', args, callback) # returns 1 if error\n\n    def lidar_ground_point_filter(self, i, output, radius=2.0, min_neighbours=0, slope_threshold=45.0, height_threshold=1.0, classify=True, slope_norm=True, height_above_ground=False, callback=None):\n        \"\"\"Identifies ground points within LiDAR dataset using a slope-based method.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        radius -- Search Radius. \n        min_neighbours -- The minimum number of neighbouring points within search areas. If fewer points than this threshold are identified during the fixed-radius search, a subsequent kNN search is performed to identify the k number of neighbours. \n        slope_threshold -- Maximum inter-point slope to be considered an off-terrain point. \n        height_threshold -- Inter-point height difference to be considered an off-terrain point. \n        classify -- Classify points as ground (2) or off-ground (1). \n        slope_norm -- Perform initial ground slope normalization?. \n        height_above_ground -- Transform output to height above average ground elevation?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--radius={}\".format(radius))\n        args.append(\"--min_neighbours={}\".format(min_neighbours))\n        args.append(\"--slope_threshold={}\".format(slope_threshold))\n        args.append(\"--height_threshold={}\".format(height_threshold))\n        if classify: args.append(\"--classify\")\n        if slope_norm: args.append(\"--slope_norm\")\n        if height_above_ground: args.append(\"--height_above_ground\")\n        return self.run_tool('lidar_ground_point_filter', args, callback) # returns 1 if error\n\n    def lidar_hex_binning(self, i, output, width, orientation=\"horizontal\", callback=None):\n        \"\"\"Hex-bins a set of LiDAR points.\n\n        Keyword arguments:\n\n        i -- Input base file. \n        output -- Output vector polygon file. \n        width -- The grid cell width. \n        orientation -- Grid Orientation, 'horizontal' or 'vertical'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--width='{}'\".format(width))\n        args.append(\"--orientation={}\".format(orientation))\n        return self.run_tool('lidar_hex_binning', args, callback) # returns 1 if error\n\n    def lidar_hillshade(self, i, output, azimuth=315.0, altitude=30.0, radius=1.0, callback=None):\n        \"\"\"Calculates a hillshade value for points within a LAS file and stores these data in the RGB field.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output file. \n        azimuth -- Illumination source azimuth in degrees. \n        altitude -- Illumination source altitude in degrees. \n        radius -- Search Radius. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--azimuth={}\".format(azimuth))\n        args.append(\"--altitude={}\".format(altitude))\n        args.append(\"--radius={}\".format(radius))\n        return self.run_tool('lidar_hillshade', args, callback) # returns 1 if error\n\n    def lidar_histogram(self, i, output, parameter=\"elevation\", clip=1.0, callback=None):\n        \"\"\"Creates a histogram of LiDAR data.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        parameter -- Parameter; options are 'elevation' (default), 'intensity', 'scan angle', 'class', 'time'. \n        clip -- Amount to clip distribution tails (in percent). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--parameter={}\".format(parameter))\n        args.append(\"--clip={}\".format(clip))\n        return self.run_tool('lidar_histogram', args, callback) # returns 1 if error\n\n    def lidar_idw_interpolation(self, i=None, output=None, parameter=\"elevation\", returns=\"all\", resolution=1.0, weight=1.0, radius=2.5, exclude_cls=None, minz=None, maxz=None, callback=None):\n        \"\"\"Interpolates LAS files using an inverse-distance weighted (IDW) scheme. When the input/output parameters are not specified, the tool interpolates all LAS files contained within the working directory.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file (including extension). \n        output -- Output raster file (including extension). \n        parameter -- Interpolation parameter; options are 'elevation' (default), 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data'. \n        returns -- Point return types to include; options are 'all' (default), 'last', 'first'. \n        resolution -- Output raster's grid resolution. \n        weight -- IDW weight value. \n        radius -- Search Radius. \n        exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. \n        minz -- Optional minimum elevation for inclusion in interpolation. \n        maxz -- Optional maximum elevation for inclusion in interpolation. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--parameter={}\".format(parameter))\n        args.append(\"--returns={}\".format(returns))\n        args.append(\"--resolution={}\".format(resolution))\n        args.append(\"--weight={}\".format(weight))\n        args.append(\"--radius={}\".format(radius))\n        if exclude_cls is not None: args.append(\"--exclude_cls='{}'\".format(exclude_cls))\n        if minz is not None: args.append(\"--minz='{}'\".format(minz))\n        if maxz is not None: args.append(\"--maxz='{}'\".format(maxz))\n        return self.run_tool('lidar_idw_interpolation', args, callback) # returns 1 if error\n\n    def lidar_info(self, i, output, density=True, vlr=True, geokeys=True, callback=None):\n        \"\"\"Prints information about a LiDAR (LAS) dataset, including header, point return frequency, and classification data and information about the variable length records (VLRs) and geokeys.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output HTML file for summary report. \n        density -- Flag indicating whether or not to calculate the average point density and nominal point spacing. \n        vlr -- Flag indicating whether or not to print the variable length records (VLRs). \n        geokeys -- Flag indicating whether or not to print the geokeys. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if density: args.append(\"--density\")\n        if vlr: args.append(\"--vlr\")\n        if geokeys: args.append(\"--geokeys\")\n        return self.run_tool('lidar_info', args, callback) # returns 1 if error\n\n    def lidar_join(self, inputs, output, callback=None):\n        \"\"\"Joins multiple LiDAR (LAS) files into a single LAS file.\n\n        Keyword arguments:\n\n        inputs -- Input LiDAR files. \n        output -- Output LiDAR file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('lidar_join', args, callback) # returns 1 if error\n\n    def lidar_kappa_index(self, input1, input2, output, class_accuracy, resolution=1.0, callback=None):\n        \"\"\"Performs a kappa index of agreement (KIA) analysis on the classifications of two LAS files.\n\n        Keyword arguments:\n\n        input1 -- Input LiDAR classification file. \n        input2 -- Input LiDAR reference file. \n        output -- Output HTML file. \n        class_accuracy -- Output classification accuracy raster file. \n        resolution -- Output raster's grid resolution. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--class_accuracy='{}'\".format(class_accuracy))\n        args.append(\"--resolution={}\".format(resolution))\n        return self.run_tool('lidar_kappa_index', args, callback) # returns 1 if error\n\n    def lidar_nearest_neighbour_gridding(self, i=None, output=None, parameter=\"elevation\", returns=\"all\", resolution=1.0, radius=2.5, exclude_cls=None, minz=None, maxz=None, callback=None):\n        \"\"\"Grids LiDAR files using nearest-neighbour scheme. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file (including extension). \n        output -- Output raster file (including extension). \n        parameter -- Interpolation parameter; options are 'elevation' (default), 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data', 'time'. \n        returns -- Point return types to include; options are 'all' (default), 'last', 'first'. \n        resolution -- Output raster's grid resolution. \n        radius -- Search Radius. \n        exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. \n        minz -- Optional minimum elevation for inclusion in interpolation. \n        maxz -- Optional maximum elevation for inclusion in interpolation. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--parameter={}\".format(parameter))\n        args.append(\"--returns={}\".format(returns))\n        args.append(\"--resolution={}\".format(resolution))\n        args.append(\"--radius={}\".format(radius))\n        if exclude_cls is not None: args.append(\"--exclude_cls='{}'\".format(exclude_cls))\n        if minz is not None: args.append(\"--minz='{}'\".format(minz))\n        if maxz is not None: args.append(\"--maxz='{}'\".format(maxz))\n        return self.run_tool('lidar_nearest_neighbour_gridding', args, callback) # returns 1 if error\n\n    def lidar_point_density(self, i=None, output=None, returns=\"all\", resolution=1.0, radius=2.5, exclude_cls=None, minz=None, maxz=None, callback=None):\n        \"\"\"Calculates the spatial pattern of point density for a LiDAR data set. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file (including extension). \n        output -- Output raster file (including extension). \n        returns -- Point return types to include; options are 'all' (default), 'last', 'first'. \n        resolution -- Output raster's grid resolution. \n        radius -- Search radius. \n        exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. \n        minz -- Optional minimum elevation for inclusion in interpolation. \n        maxz -- Optional maximum elevation for inclusion in interpolation. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--returns={}\".format(returns))\n        args.append(\"--resolution={}\".format(resolution))\n        args.append(\"--radius={}\".format(radius))\n        if exclude_cls is not None: args.append(\"--exclude_cls='{}'\".format(exclude_cls))\n        if minz is not None: args.append(\"--minz='{}'\".format(minz))\n        if maxz is not None: args.append(\"--maxz='{}'\".format(maxz))\n        return self.run_tool('lidar_point_density', args, callback) # returns 1 if error\n\n    def lidar_point_return_analysis(self, i, output=None, callback=None):\n        \"\"\"This tool performs a quality control check on the return values of points in a LiDAR file.\n\n        Keyword arguments:\n\n        i -- Name of the input LiDAR points. \n        output -- Name of the output LiDAR points. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        return self.run_tool('lidar_point_return_analysis', args, callback) # returns 1 if error\n\n    def lidar_point_stats(self, i=None, resolution=1.0, num_points=True, num_pulses=False, avg_points_per_pulse=True, z_range=False, intensity_range=False, predom_class=False, callback=None):\n        \"\"\"Creates several rasters summarizing the distribution of LAS point data. When the input/output parameters are not specified, the tool works on all LAS files contained within the working directory.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        resolution -- Output raster's grid resolution. \n        num_points -- Flag indicating whether or not to output the number of points (returns) raster. \n        num_pulses -- Flag indicating whether or not to output the number of pulses raster. \n        avg_points_per_pulse -- Flag indicating whether or not to output the average number of points (returns) per pulse raster. \n        z_range -- Flag indicating whether or not to output the elevation range raster. \n        intensity_range -- Flag indicating whether or not to output the intensity range raster. \n        predom_class -- Flag indicating whether or not to output the predominant classification raster. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        args.append(\"--resolution={}\".format(resolution))\n        if num_points: args.append(\"--num_points\")\n        if num_pulses: args.append(\"--num_pulses\")\n        if avg_points_per_pulse: args.append(\"--avg_points_per_pulse\")\n        if z_range: args.append(\"--z_range\")\n        if intensity_range: args.append(\"--intensity_range\")\n        if predom_class: args.append(\"--predom_class\")\n        return self.run_tool('lidar_point_stats', args, callback) # returns 1 if error\n\n    def lidar_ransac_planes(self, i, output, radius=2.0, num_iter=50, num_samples=5, threshold=0.35, model_size=8, max_slope=80.0, classify=False, last_returns=False, callback=None):\n        \"\"\"Performs a RANSAC analysis to identify points within a LiDAR point cloud that belong to linear planes.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        radius -- Search Radius. \n        num_iter -- Number of iterations. \n        num_samples -- Number of sample points on which to build the model. \n        threshold -- Threshold used to determine inlier points. \n        model_size -- Acceptable model size. \n        max_slope -- Maximum planar slope. \n        classify -- Classify points as ground (2) or off-ground (1). \n        last_returns -- Only include last- and only-return points. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--radius={}\".format(radius))\n        args.append(\"--num_iter={}\".format(num_iter))\n        args.append(\"--num_samples={}\".format(num_samples))\n        args.append(\"--threshold={}\".format(threshold))\n        args.append(\"--model_size={}\".format(model_size))\n        args.append(\"--max_slope={}\".format(max_slope))\n        if classify: args.append(\"--classify\")\n        if last_returns: args.append(\"--last_returns\")\n        return self.run_tool('lidar_ransac_planes', args, callback) # returns 1 if error\n\n    def lidar_rbf_interpolation(self, i=None, output=None, parameter=\"elevation\", returns=\"all\", resolution=1.0, num_points=20, exclude_cls=None, minz=None, maxz=None, func_type=\"ThinPlateSpline\", poly_order=\"none\", weight=5, callback=None):\n        \"\"\"Interpolates LAS files using a radial basis function (RBF) scheme. When the input/output parameters are not specified, the tool interpolates all LAS files contained within the working directory.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file (including extension). \n        output -- Output raster file (including extension). \n        parameter -- Interpolation parameter; options are 'elevation' (default), 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data'. \n        returns -- Point return types to include; options are 'all' (default), 'last', 'first'. \n        resolution -- Output raster's grid resolution. \n        num_points -- Number of points. \n        exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. \n        minz -- Optional minimum elevation for inclusion in interpolation. \n        maxz -- Optional maximum elevation for inclusion in interpolation. \n        func_type -- Radial basis function type; options are 'ThinPlateSpline' (default), 'PolyHarmonic', 'Gaussian', 'MultiQuadric', 'InverseMultiQuadric'. \n        poly_order -- Polynomial order; options are 'none' (default), 'constant', 'affine'. \n        weight -- Weight parameter used in basis function. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--parameter={}\".format(parameter))\n        args.append(\"--returns={}\".format(returns))\n        args.append(\"--resolution={}\".format(resolution))\n        args.append(\"--num_points={}\".format(num_points))\n        if exclude_cls is not None: args.append(\"--exclude_cls='{}'\".format(exclude_cls))\n        if minz is not None: args.append(\"--minz='{}'\".format(minz))\n        if maxz is not None: args.append(\"--maxz='{}'\".format(maxz))\n        args.append(\"--func_type={}\".format(func_type))\n        args.append(\"--poly_order={}\".format(poly_order))\n        args.append(\"--weight={}\".format(weight))\n        return self.run_tool('lidar_rbf_interpolation', args, callback) # returns 1 if error\n\n    def lidar_remove_duplicates(self, i, output, include_z=False, callback=None):\n        \"\"\"Removes duplicate points from a LiDAR data set.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        include_z -- Include z-values in point comparison?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if include_z: args.append(\"--include_z\")\n        return self.run_tool('lidar_remove_duplicates', args, callback) # returns 1 if error\n\n    def lidar_remove_outliers(self, i, output, radius=2.0, elev_diff=50.0, use_median=False, classify=True, callback=None):\n        \"\"\"Removes outliers (high and low points) in a LiDAR point cloud.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        radius -- Search Radius. \n        elev_diff -- Max. elevation difference. \n        use_median -- Optional flag indicating whether to use the difference from median elevation rather than mean. \n        classify -- Classify points as ground (2) or off-ground (1). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--radius={}\".format(radius))\n        args.append(\"--elev_diff={}\".format(elev_diff))\n        if use_median: args.append(\"--use_median\")\n        if classify: args.append(\"--classify\")\n        return self.run_tool('lidar_remove_outliers', args, callback) # returns 1 if error\n\n    def lidar_rooftop_analysis(self, buildings, output, i=None, radius=2.0, num_iter=50, num_samples=10, threshold=0.15, model_size=15, max_slope=65.0, norm_diff=10.0, azimuth=180.0, altitude=30.0, callback=None):\n        \"\"\"Identifies roof segments in a LiDAR point cloud.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        buildings -- Input vector build footprint polygons file. \n        output -- Output vector polygon file. \n        radius -- Search Radius. \n        num_iter -- Number of iterations. \n        num_samples -- Number of sample points on which to build the model. \n        threshold -- Threshold used to determine inlier points (in elevation units). \n        model_size -- Acceptable model size, in points. \n        max_slope -- Maximum planar slope, in degrees. \n        norm_diff -- Maximum difference in normal vectors, in degrees. \n        azimuth -- Illumination source azimuth, in degrees. \n        altitude -- Illumination source altitude in degrees. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        args.append(\"--buildings='{}'\".format(buildings))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--radius={}\".format(radius))\n        args.append(\"--num_iter={}\".format(num_iter))\n        args.append(\"--num_samples={}\".format(num_samples))\n        args.append(\"--threshold={}\".format(threshold))\n        args.append(\"--model_size={}\".format(model_size))\n        args.append(\"--max_slope={}\".format(max_slope))\n        args.append(\"--norm_diff={}\".format(norm_diff))\n        args.append(\"--azimuth={}\".format(azimuth))\n        args.append(\"--altitude={}\".format(altitude))\n        return self.run_tool('lidar_rooftop_analysis', args, callback) # returns 1 if error\n\n    def lidar_segmentation(self, i, output, radius=2.0, num_iter=50, num_samples=10, threshold=0.15, model_size=15, max_slope=80.0, norm_diff=10.0, maxzdiff=1.0, classes=False, ground=False, callback=None):\n        \"\"\"Segments a LiDAR point cloud based on differences in the orientation of fitted planar surfaces and point proximity.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        radius -- Search Radius. \n        num_iter -- Number of iterations. \n        num_samples -- Number of sample points on which to build the model. \n        threshold -- Threshold used to determine inlier points. \n        model_size -- Acceptable model size. \n        max_slope -- Maximum planar slope. \n        norm_diff -- Maximum difference in normal vectors, in degrees. \n        maxzdiff -- Maximum difference in elevation (z units) between neighbouring points of the same segment. \n        classes -- Segments don't cross class boundaries. \n        ground -- Classify the largest segment as ground points?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--radius={}\".format(radius))\n        args.append(\"--num_iter={}\".format(num_iter))\n        args.append(\"--num_samples={}\".format(num_samples))\n        args.append(\"--threshold={}\".format(threshold))\n        args.append(\"--model_size={}\".format(model_size))\n        args.append(\"--max_slope={}\".format(max_slope))\n        args.append(\"--norm_diff={}\".format(norm_diff))\n        args.append(\"--maxzdiff={}\".format(maxzdiff))\n        if classes: args.append(\"--classes\")\n        if ground: args.append(\"--ground\")\n        return self.run_tool('lidar_segmentation', args, callback) # returns 1 if error\n\n    def lidar_segmentation_based_filter(self, i, output, radius=5.0, norm_diff=2.0, maxzdiff=1.0, classify=False, callback=None):\n        \"\"\"Identifies ground points within LiDAR point clouds using a segmentation based approach.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output file. \n        radius -- Search Radius. \n        norm_diff -- Maximum difference in normal vectors, in degrees. \n        maxzdiff -- Maximum difference in elevation (z units) between neighbouring points of the same segment. \n        classify -- Classify points as ground (2) or off-ground (1). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--radius={}\".format(radius))\n        args.append(\"--norm_diff={}\".format(norm_diff))\n        args.append(\"--maxzdiff={}\".format(maxzdiff))\n        if classify: args.append(\"--classify\")\n        return self.run_tool('lidar_segmentation_based_filter', args, callback) # returns 1 if error\n\n    def lidar_shift(self, i, output, x_shift=\"\", y_shift=\"\", z_shift=\"\", callback=None):\n        \"\"\"Shifts the x,y,z coordinates of a LiDAR file.\n\n        Keyword arguments:\n\n        i -- Name of the input LiDAR points. \n        output -- Name of the output LiDAR points. \n        x_shift -- x-shift value, blank for none. \n        y_shift -- y-shift value, blank for none. \n        z_shift -- z-shift value, blank for none. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--x_shift={}\".format(x_shift))\n        args.append(\"--y_shift={}\".format(y_shift))\n        args.append(\"--z_shift={}\".format(z_shift))\n        return self.run_tool('lidar_shift', args, callback) # returns 1 if error\n\n    def lidar_sibson_interpolation(self, i=None, output=None, parameter=\"elevation\", returns=\"all\", resolution=1.0, exclude_cls=None, minz=None, maxz=None, callback=None):\n        \"\"\"This tool interpolates one or more LiDAR tiles using Sibson's natural neighbour method.\n\n        Keyword arguments:\n\n        i -- Name of the input LiDAR points (leave blank to use all files in WorkingDirectory. \n        output -- Output raster file (including extension). \n        parameter -- Interpolation parameter; options are 'elevation' (default), 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'user_data'. \n        returns -- Point return types to include; options are 'all' (default), 'last', 'first'. \n        resolution -- Output raster's grid resolution. \n        exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. \n        minz -- Optional minimum elevation for inclusion in interpolation. \n        maxz -- Optional maximum elevation for inclusion in interpolation. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--parameter={}\".format(parameter))\n        args.append(\"--returns={}\".format(returns))\n        args.append(\"--resolution={}\".format(resolution))\n        if exclude_cls is not None: args.append(\"--exclude_cls='{}'\".format(exclude_cls))\n        if minz is not None: args.append(\"--minz='{}'\".format(minz))\n        if maxz is not None: args.append(\"--maxz='{}'\".format(maxz))\n        return self.run_tool('lidar_sibson_interpolation', args, callback) # returns 1 if error\n\n    def lidar_sort_by_time(self, i, output, callback=None):\n        \"\"\"This tool sorts the points in a LiDAR file by the GPS time.\n\n        Keyword arguments:\n\n        i -- Name of the input LiDAR points. \n        output -- Name of the output LiDAR points. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('lidar_sort_by_time', args, callback) # returns 1 if error\n\n    def lidar_thin(self, i, output, resolution=2.0, method=\"lowest\", save_filtered=False, callback=None):\n        \"\"\"Thins a LiDAR point cloud, reducing point density.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        resolution -- The size of the square area used to evaluate nearby points in the LiDAR data. \n        method -- Point selection method; options are 'first', 'last', 'lowest' (default), 'highest', 'nearest'. \n        save_filtered -- Save filtered points to separate file?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--resolution={}\".format(resolution))\n        args.append(\"--method={}\".format(method))\n        if save_filtered: args.append(\"--save_filtered\")\n        return self.run_tool('lidar_thin', args, callback) # returns 1 if error\n\n    def lidar_thin_high_density(self, i, output, density, resolution=1.0, save_filtered=False, callback=None):\n        \"\"\"Thins points from high density areas within a LiDAR point cloud.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        resolution -- Output raster's grid resolution. \n        density -- Max. point density (points / m^3). \n        save_filtered -- Save filtered points to separate file?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--resolution={}\".format(resolution))\n        args.append(\"--density='{}'\".format(density))\n        if save_filtered: args.append(\"--save_filtered\")\n        return self.run_tool('lidar_thin_high_density', args, callback) # returns 1 if error\n\n    def lidar_tile(self, i, width=1000.0, height=1000.0, origin_x=0.0, origin_y=0.0, min_points=2, callback=None):\n        \"\"\"Tiles a LiDAR LAS file into multiple LAS files.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        width -- Width of tiles in the X dimension; default 1000.0. \n        height -- Height of tiles in the Y dimension. \n        origin_x -- Origin point X coordinate for tile grid. \n        origin_y -- Origin point Y coordinate for tile grid. \n        min_points -- Minimum number of points contained in a tile for it to be saved. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--width={}\".format(width))\n        args.append(\"--height={}\".format(height))\n        args.append(\"--origin_x={}\".format(origin_x))\n        args.append(\"--origin_y={}\".format(origin_y))\n        args.append(\"--min_points={}\".format(min_points))\n        return self.run_tool('lidar_tile', args, callback) # returns 1 if error\n\n    def lidar_tile_footprint(self, output, i=None, hull=False, callback=None):\n        \"\"\"Creates a vector polygon of the convex hull of a LiDAR point cloud. When the input/output parameters are not specified, the tool works with all LAS files contained within the working directory.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output vector polygon file. \n        hull -- Identify the convex hull around points. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if hull: args.append(\"--hull\")\n        return self.run_tool('lidar_tile_footprint', args, callback) # returns 1 if error\n\n    def lidar_tin_gridding(self, i=None, output=None, parameter=\"elevation\", returns=\"all\", resolution=1.0, exclude_cls=\"7,18\", minz=None, maxz=None, max_triangle_edge_length=None, callback=None):\n        \"\"\"Creates a raster grid based on a Delaunay triangular irregular network (TIN) fitted to LiDAR points.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file (including extension). \n        output -- Output raster file (including extension). \n        parameter -- Interpolation parameter; options are 'elevation' (default), 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data'. \n        returns -- Point return types to include; options are 'all' (default), 'last', 'first'. \n        resolution -- Output raster's grid resolution. \n        exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. \n        minz -- Optional minimum elevation for inclusion in interpolation. \n        maxz -- Optional maximum elevation for inclusion in interpolation. \n        max_triangle_edge_length -- Optional maximum triangle edge length; triangles larger than this size will not be gridded. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--parameter={}\".format(parameter))\n        args.append(\"--returns={}\".format(returns))\n        args.append(\"--resolution={}\".format(resolution))\n        args.append(\"--exclude_cls={}\".format(exclude_cls))\n        if minz is not None: args.append(\"--minz='{}'\".format(minz))\n        if maxz is not None: args.append(\"--maxz='{}'\".format(maxz))\n        if max_triangle_edge_length is not None: args.append(\"--max_triangle_edge_length='{}'\".format(max_triangle_edge_length))\n        return self.run_tool('lidar_tin_gridding', args, callback) # returns 1 if error\n\n    def lidar_tophat_transform(self, i, output, radius=1.0, callback=None):\n        \"\"\"Performs a white top-hat transform on a Lidar dataset; as an estimate of height above ground, this is useful for modelling the vegetation canopy.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        radius -- Search Radius. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--radius={}\".format(radius))\n        return self.run_tool('lidar_tophat_transform', args, callback) # returns 1 if error\n\n    def modify_lidar(self, i=None, output=None, statement=\"\", callback=None):\n        \"\"\"Modify points within a LiDAR point cloud based on point properties.\n\n        Keyword arguments:\n\n        i -- Name of the input LiDAR points. \n        output -- Name of the output LiDAR points. \n        statement -- Modify statement e.g. x += 5000.0. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--statement={}\".format(statement))\n        return self.run_tool('modify_lidar', args, callback) # returns 1 if error\n\n    def normal_vectors(self, i, output, radius=1.0, callback=None):\n        \"\"\"Calculates normal vectors for points within a LAS file and stores these data (XYZ vector components) in the RGB field.\n\n        Keyword arguments:\n\n        i -- Input LiDAR file. \n        output -- Output LiDAR file. \n        radius -- Search Radius. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--radius={}\".format(radius))\n        return self.run_tool('normal_vectors', args, callback) # returns 1 if error\n\n    def normalize_lidar(self, i, output, dtm, callback=None):\n        \"\"\"Normalizes a LiDAR point cloud.\n\n        Keyword arguments:\n\n        i -- Name of the input LiDAR file. \n        output -- Name of the output LiDAR file. \n        dtm -- Name of the input digital terrain model (DTM) raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--dtm='{}'\".format(dtm))\n        return self.run_tool('normalize_lidar', args, callback) # returns 1 if error\n\n    def recover_flightline_info(self, i, output, max_time_diff=5.0, pt_src_id=False, user_data=False, rgb=False, callback=None):\n        \"\"\"Associates LiDAR points by their flightlines.\n\n        Keyword arguments:\n\n        i -- Name of the input LiDAR points. \n        output -- Name of the output LiDAR points. \n        max_time_diff -- Maximum in-flightline time difference (seconds). \n        pt_src_id -- Add flightline information to the point source ID. \n        user_data -- Add flightline information to the user data. \n        rgb -- Add flightline information to the RGB colour data. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--max_time_diff={}\".format(max_time_diff))\n        if pt_src_id: args.append(\"--pt_src_id\")\n        if user_data: args.append(\"--user_data\")\n        if rgb: args.append(\"--rgb\")\n        return self.run_tool('recover_flightline_info', args, callback) # returns 1 if error\n\n    def select_tiles_by_polygon(self, indir, outdir, polygons, callback=None):\n        \"\"\"Copies LiDAR tiles overlapping with a polygon into an output directory.\n\n        Keyword arguments:\n\n        indir -- Input LAS file source directory. \n        outdir -- Output directory into which LAS files within the polygon are copied. \n        polygons -- Input vector polygons file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--indir='{}'\".format(indir))\n        args.append(\"--outdir='{}'\".format(outdir))\n        args.append(\"--polygons='{}'\".format(polygons))\n        return self.run_tool('select_tiles_by_polygon', args, callback) # returns 1 if error\n\n    def sort_lidar(self, i=None, output=None, criteria=\"\", callback=None):\n        \"\"\"Sorts LiDAR points based on their properties.\n\n        Keyword arguments:\n\n        i -- Name of the input LiDAR points. \n        output -- Name of the output LiDAR points. \n        criteria -- Sort criteria e.g. 'x 50.0, y 50.0, z'; criteria may include x, y, z, intensity, class, user_data, point_source_id, and scan_angle. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--criteria={}\".format(criteria))\n        return self.run_tool('sort_lidar', args, callback) # returns 1 if error\n\n    def split_lidar(self, i=None, criterion=\"num_pts\", interval=\"\", min_pts=5, callback=None):\n        \"\"\"Splits LiDAR points up into a series of new files based on their properties.\n\n        Keyword arguments:\n\n        i -- Name of the input LiDAR points. \n        criterion -- Criterion on which to base the split of the input file. Options include 'num_pts, 'x', 'y', 'z', intensity, 'class', 'user_data', 'point_source_id', 'scan_angle', 'time'. \n        interval -- Interval. \n        min_pts -- Minimum number of points in an output file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if i is not None: args.append(\"--input='{}'\".format(i))\n        args.append(\"--criterion={}\".format(criterion))\n        args.append(\"--interval={}\".format(interval))\n        args.append(\"--min_pts={}\".format(min_pts))\n        return self.run_tool('split_lidar', args, callback) # returns 1 if error\n\n    def zlidar_to_las(self, inputs=None, outdir=None, callback=None):\n        \"\"\"Converts one or more zlidar files into the LAS data format.\n\n        Keyword arguments:\n\n        inputs -- Input ZLidar files. \n        outdir -- Output directory into which zlidar files are created. If unspecified, it is assumed to be the same as the inputs. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if inputs is not None: args.append(\"--inputs='{}'\".format(inputs))\n        if outdir is not None: args.append(\"--outdir='{}'\".format(outdir))\n        return self.run_tool('zlidar_to_las', args, callback) # returns 1 if error\n\n    ####################\n    # Machine Learning #\n    ####################\n\n    def dbscan(self, inputs, output, scaling=\"Normalize\", search_dist=0.01, min_points=5, callback=None):\n        \"\"\"Performs a DBSCAN-based unsupervised clustering operation.\n\n        Keyword arguments:\n\n        inputs -- Names of the input rasters. \n        scaling -- Scaling method for predictors. Options include 'None', 'Normalize', and 'Standardize'. \n        output -- Name of the output raster file. \n        search_dist -- Search-distance parameter. \n        min_points -- Minimum point density needed to define 'core' point in cluster. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--scaling={}\".format(scaling))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--search_dist={}\".format(search_dist))\n        args.append(\"--min_points={}\".format(min_points))\n        return self.run_tool('dbscan', args, callback) # returns 1 if error\n\n    def k_means_clustering(self, inputs, output, classes, out_html=None, max_iterations=10, class_change=2.0, initialize=\"diagonal\", min_class_size=10, callback=None):\n        \"\"\"Performs a k-means clustering operation on a multi-spectral dataset.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        out_html -- Output HTML report file. \n        classes -- Number of classes. \n        max_iterations -- Maximum number of iterations. \n        class_change -- Minimum percent of cells changed between iterations before completion. \n        initialize -- How to initialize cluster centres?. \n        min_class_size -- Minimum class size, in pixels. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        if out_html is not None: args.append(\"--out_html='{}'\".format(out_html))\n        args.append(\"--classes='{}'\".format(classes))\n        args.append(\"--max_iterations={}\".format(max_iterations))\n        args.append(\"--class_change={}\".format(class_change))\n        args.append(\"--initialize={}\".format(initialize))\n        args.append(\"--min_class_size={}\".format(min_class_size))\n        return self.run_tool('k_means_clustering', args, callback) # returns 1 if error\n\n    def knn_classification(self, inputs, training, field, scaling=\"Normalize\", output=None, k=5, clip=True, test_proportion=0.2, callback=None):\n        \"\"\"Performs a supervised k-nearest neighbour classification using training site polygons/points and predictor rasters.\n\n        Keyword arguments:\n\n        inputs -- Names of the input predictor rasters. \n        scaling -- Scaling method for predictors. Options include 'None', 'Normalize', and 'Standardize'. \n        training -- Name of the input training site polygons/points shapefile. \n        field -- Name of the attribute containing class name data. \n        output -- Name of the output raster file. \n        k -- k-parameter, which determines the number of nearest neighbours used. \n        clip -- Perform training data clipping to remove outlier pixels?. \n        test_proportion -- The proportion of the dataset to include in the test split; default is 0.2. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--scaling={}\".format(scaling))\n        args.append(\"--training='{}'\".format(training))\n        args.append(\"--field='{}'\".format(field))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"-k={}\".format(k))\n        if clip: args.append(\"--clip\")\n        args.append(\"--test_proportion={}\".format(test_proportion))\n        return self.run_tool('knn_classification', args, callback) # returns 1 if error\n\n    def knn_regression(self, inputs, training, field, scaling=\"Normalize\", output=None, k=5, weight=True, test_proportion=0.2, callback=None):\n        \"\"\"Performs a supervised k-nearest neighbour regression using training site points and predictor rasters.\n\n        Keyword arguments:\n\n        inputs -- Names of the input predictor rasters. \n        scaling -- Scaling method for predictors. Options include 'None', 'Normalize', and 'Standardize'. \n        training -- Name of the input training site points Shapefile. \n        field -- Name of the attribute containing response variable name data. \n        output -- Name of the output raster file. \n        k -- k-parameter, which determines the number of nearest neighbours used. \n        weight -- Use distance weighting?. \n        test_proportion -- The proportion of the dataset to include in the test split; default is 0.2. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--scaling={}\".format(scaling))\n        args.append(\"--training='{}'\".format(training))\n        args.append(\"--field='{}'\".format(field))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"-k={}\".format(k))\n        if weight: args.append(\"--weight\")\n        args.append(\"--test_proportion={}\".format(test_proportion))\n        return self.run_tool('knn_regression', args, callback) # returns 1 if error\n\n    def logistic_regression(self, inputs, training, field, scaling=\"Normalize\", output=None, test_proportion=0.2, callback=None):\n        \"\"\"Performs a logistic regression analysis using training site polygons/points and predictor rasters.\n\n        Keyword arguments:\n\n        inputs -- Names of the input predictor rasters. \n        scaling -- Scaling method for predictors. Options include 'None', 'Normalize', and 'Standardize'. \n        training -- Name of the input training site polygons/points shapefile. \n        field -- Name of the attribute containing class data. \n        output -- Name of the output raster file. \n        test_proportion -- The proportion of the dataset to include in the test split; default is 0.2. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--scaling={}\".format(scaling))\n        args.append(\"--training='{}'\".format(training))\n        args.append(\"--field='{}'\".format(field))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--test_proportion={}\".format(test_proportion))\n        return self.run_tool('logistic_regression', args, callback) # returns 1 if error\n\n    def modified_k_means_clustering(self, inputs, output, out_html=None, start_clusters=1000, merge_dist=None, max_iterations=10, class_change=2.0, callback=None):\n        \"\"\"Performs a modified k-means clustering operation on a multi-spectral dataset.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output raster file. \n        out_html -- Output HTML report file. \n        start_clusters -- Initial number of clusters. \n        merge_dist -- Cluster merger distance. \n        max_iterations -- Maximum number of iterations. \n        class_change -- Minimum percent of cells changed between iterations before completion. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        if out_html is not None: args.append(\"--out_html='{}'\".format(out_html))\n        args.append(\"--start_clusters={}\".format(start_clusters))\n        if merge_dist is not None: args.append(\"--merge_dist='{}'\".format(merge_dist))\n        args.append(\"--max_iterations={}\".format(max_iterations))\n        args.append(\"--class_change={}\".format(class_change))\n        return self.run_tool('modified_k_means_clustering', args, callback) # returns 1 if error\n\n    def random_forest_classification(self, inputs, training, field, output=None, split_criterion=\"Gini\", n_trees=500, min_samples_leaf=1, min_samples_split=2, test_proportion=0.2, callback=None):\n        \"\"\"Performs a supervised random forest classification using training site polygons/points and predictor rasters.\n\n        Keyword arguments:\n\n        inputs -- Names of the input predictor rasters. \n        training -- Name of the input training site polygons/points shapefile. \n        field -- Name of the attribute containing class data. \n        output -- Name of the output raster file. \n        split_criterion -- Split criterion to use when building a tree. Options include 'Gini', 'Entropy', and 'ClassificationError'. \n        n_trees -- The number of trees in the forest. \n        min_samples_leaf -- The minimum number of samples required to be at a leaf node. \n        min_samples_split -- The minimum number of samples required to split an internal node. \n        test_proportion -- The proportion of the dataset to include in the test split; default is 0.2. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--training='{}'\".format(training))\n        args.append(\"--field='{}'\".format(field))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--split_criterion={}\".format(split_criterion))\n        args.append(\"--n_trees={}\".format(n_trees))\n        args.append(\"--min_samples_leaf={}\".format(min_samples_leaf))\n        args.append(\"--min_samples_split={}\".format(min_samples_split))\n        args.append(\"--test_proportion={}\".format(test_proportion))\n        return self.run_tool('random_forest_classification', args, callback) # returns 1 if error\n\n    def random_forest_regression(self, inputs, training, field, output=None, n_trees=100, min_samples_leaf=1, min_samples_split=2, test_proportion=0.2, callback=None):\n        \"\"\"Performs a random forest regression analysis using training site data and predictor rasters.\n\n        Keyword arguments:\n\n        inputs -- Names of the input predictor rasters. \n        training -- Name of the input training site points shapefile. \n        field -- Name of the attribute containing response variable name data. \n        output -- Name of the output raster file. This parameter is optional. When unspecified, the tool will only build the model. When specified, the tool will use the built model and predictor rasters to perform a spatial prediction. \n        n_trees -- The number of trees in the forest. \n        min_samples_leaf -- The minimum number of samples required to be at a leaf node. \n        min_samples_split -- The minimum number of samples required to split an internal node. \n        test_proportion -- The proportion of the dataset to include in the test split; default is 0.2. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--training='{}'\".format(training))\n        args.append(\"--field='{}'\".format(field))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--n_trees={}\".format(n_trees))\n        args.append(\"--min_samples_leaf={}\".format(min_samples_leaf))\n        args.append(\"--min_samples_split={}\".format(min_samples_split))\n        args.append(\"--test_proportion={}\".format(test_proportion))\n        return self.run_tool('random_forest_regression', args, callback) # returns 1 if error\n\n    def svm_classification(self, inputs, training, field, scaling=\"Normalize\", output=None, c=200.0, gamma=50.0, tolerance=0.1, test_proportion=0.2, callback=None):\n        \"\"\"Performs an SVM binary classification using training site polygons/points and multiple input images.\n\n        Keyword arguments:\n\n        inputs -- Names of the input predictor rasters. \n        scaling -- Scaling method for predictors. Options include 'None', 'Normalize', and 'Standardize'. \n        training -- Name of the input training site polygons/points Shapefile. \n        field -- Name of the attribute containing class data. \n        output -- Name of the output raster file. \n        c -- c-value, the regularization parameter. \n        gamma -- Gamma parameter used in setting the RBF (Gaussian) kernel function. \n        tolerance -- The tolerance parameter used in determining the stopping condition. \n        test_proportion -- The proportion of the dataset to include in the test split; default is 0.2. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--scaling={}\".format(scaling))\n        args.append(\"--training='{}'\".format(training))\n        args.append(\"--field='{}'\".format(field))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"-c={}\".format(c))\n        args.append(\"--gamma={}\".format(gamma))\n        args.append(\"--tolerance={}\".format(tolerance))\n        args.append(\"--test_proportion={}\".format(test_proportion))\n        return self.run_tool('svm_classification', args, callback) # returns 1 if error\n\n    def svm_regression(self, inputs, training, field, scaling=\"Normalize\", output=None, c=50.0, eps=10.0, gamma=0.5, test_proportion=0.2, callback=None):\n        \"\"\"Performs a supervised SVM regression analysis using training site points and predictor rasters.\n\n        Keyword arguments:\n\n        inputs -- Names of the input predictor rasters. \n        scaling -- Scaling method for predictors. Options include 'None', 'Normalize', and 'Standardize'. \n        training -- Name of the input training site points Shapefile. \n        field -- Name of the attribute containing class data. \n        output -- Name of the output raster file. \n        c -- c-value, the regularization parameter. \n        eps -- Epsilon in the epsilon-SVR model. \n        gamma -- Gamma parameter used in setting the RBF (Gaussian) kernel function. \n        test_proportion -- The proportion of the dataset to include in the test split; default is 0.2. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--scaling={}\".format(scaling))\n        args.append(\"--training='{}'\".format(training))\n        args.append(\"--field='{}'\".format(field))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"-c={}\".format(c))\n        args.append(\"--eps={}\".format(eps))\n        args.append(\"--gamma={}\".format(gamma))\n        args.append(\"--test_proportion={}\".format(test_proportion))\n        return self.run_tool('svm_regression', args, callback) # returns 1 if error\n\n    ########################\n    # Math and Stats Tools #\n    ########################\n\n    def And(self, input1, input2, output, callback=None):\n        \"\"\"Performs a logical AND operator on two Boolean raster images.\n\n        Keyword arguments:\n\n        input1 -- Input raster file. \n        input2 -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('and', args, callback) # returns 1 if error\n\n    def Not(self, input1, input2, output, callback=None):\n        \"\"\"Performs a logical NOT operator on two Boolean raster images.\n\n        Keyword arguments:\n\n        input1 -- Input raster file. \n        input2 -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('not', args, callback) # returns 1 if error\n\n    def Or(self, input1, input2, output, callback=None):\n        \"\"\"Performs a logical OR operator on two Boolean raster images.\n\n        Keyword arguments:\n\n        input1 -- Input raster file. \n        input2 -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('or', args, callback) # returns 1 if error\n\n    def absolute_value(self, i, output, callback=None):\n        \"\"\"Calculates the absolute value of every cell in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('absolute_value', args, callback) # returns 1 if error\n\n    def add(self, input1, input2, output, callback=None):\n        \"\"\"Performs an addition operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('add', args, callback) # returns 1 if error\n\n    def anova(self, i, features, output, callback=None):\n        \"\"\"Performs an analysis of variance (ANOVA) test on a raster dataset.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        features -- Feature definition (or class) raster. \n        output -- Output HTML file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--features='{}'\".format(features))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('anova', args, callback) # returns 1 if error\n\n    def arc_cos(self, i, output, callback=None):\n        \"\"\"Returns the inverse cosine (arccos) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('arc_cos', args, callback) # returns 1 if error\n\n    def arc_sin(self, i, output, callback=None):\n        \"\"\"Returns the inverse sine (arcsin) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('arc_sin', args, callback) # returns 1 if error\n\n    def arc_tan(self, i, output, callback=None):\n        \"\"\"Returns the inverse tangent (arctan) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('arc_tan', args, callback) # returns 1 if error\n\n    def arcosh(self, i, output, callback=None):\n        \"\"\"Returns the inverse hyperbolic cosine (arcosh) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('arcosh', args, callback) # returns 1 if error\n\n    def arsinh(self, i, output, callback=None):\n        \"\"\"Returns the inverse hyperbolic sine (arsinh) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('arsinh', args, callback) # returns 1 if error\n\n    def artanh(self, i, output, callback=None):\n        \"\"\"Returns the inverse hyperbolic tangent (arctanh) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('artanh', args, callback) # returns 1 if error\n\n    def atan2(self, input_y, input_x, output, callback=None):\n        \"\"\"Returns the 2-argument inverse tangent (atan2).\n\n        Keyword arguments:\n\n        input_y -- Input y raster file or constant value (rise). \n        input_x -- Input x raster file or constant value (run). \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input_y='{}'\".format(input_y))\n        args.append(\"--input_x='{}'\".format(input_x))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('atan2', args, callback) # returns 1 if error\n\n    def attribute_correlation(self, i, output=None, callback=None):\n        \"\"\"Performs a correlation analysis on attribute fields from a vector database.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        return self.run_tool('attribute_correlation', args, callback) # returns 1 if error\n\n    def attribute_correlation_neighbourhood_analysis(self, i, field1, field2, radius=None, min_points=None, stat=\"pearson\", callback=None):\n        \"\"\"Performs a correlation on two input vector attributes within a neighbourhood search windows.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        field1 -- First input field name (dependent variable) in attribute table. \n        field2 -- Second input field name (independent variable) in attribute table. \n        radius -- Search Radius (in map units). \n        min_points -- Minimum number of points. \n        stat -- Correlation type; one of 'pearson' (default) and 'spearman'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field1='{}'\".format(field1))\n        args.append(\"--field2='{}'\".format(field2))\n        if radius is not None: args.append(\"--radius='{}'\".format(radius))\n        if min_points is not None: args.append(\"--min_points='{}'\".format(min_points))\n        args.append(\"--stat={}\".format(stat))\n        return self.run_tool('attribute_correlation_neighbourhood_analysis', args, callback) # returns 1 if error\n\n    def attribute_histogram(self, i, field, output, callback=None):\n        \"\"\"Creates a histogram for the field values of a vector's attribute table.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        field -- Input field name in attribute table. \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field='{}'\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('attribute_histogram', args, callback) # returns 1 if error\n\n    def attribute_scattergram(self, i, fieldx, fieldy, output, trendline=False, callback=None):\n        \"\"\"Creates a scattergram for two field values of a vector's attribute table.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        fieldx -- Input field name in attribute table for the x-axis. \n        fieldy -- Input field name in attribute table for the y-axis. \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        trendline -- Draw the trendline. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--fieldx='{}'\".format(fieldx))\n        args.append(\"--fieldy='{}'\".format(fieldy))\n        args.append(\"--output='{}'\".format(output))\n        if trendline: args.append(\"--trendline\")\n        return self.run_tool('attribute_scattergram', args, callback) # returns 1 if error\n\n    def ceil(self, i, output, callback=None):\n        \"\"\"Returns the smallest (closest to negative infinity) value that is greater than or equal to the values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('ceil', args, callback) # returns 1 if error\n\n    def conditional_evaluation(self, i, output, statement=\"\", true=None, false=None, callback=None):\n        \"\"\"Performs a conditional evaluation (if-then-else) operation on a raster.\n\n        Keyword arguments:\n\n        i -- Name of the input raster file. \n        statement -- Conditional statement e.g. value > 35.0. This statement must be a valid Rust statement. \n        true -- Value where condition evaluates TRUE (input raster or constant value). \n        false -- Value where condition evaluates FALSE (input raster or constant value). \n        output -- Name of the output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--statement={}\".format(statement))\n        if true is not None: args.append(\"--true='{}'\".format(true))\n        if false is not None: args.append(\"--false='{}'\".format(false))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('conditional_evaluation', args, callback) # returns 1 if error\n\n    def conditioned_latin_hypercube(self, inputs, output, samples=500, iterations=25000, seed=None, prob=0.5, threshold=None, temp=1.0, temp_decay=0.05, cycle=10, average=False, callback=None):\n        \"\"\"Implements conditioned Latin Hypercube sampling.\n\n        Keyword arguments:\n\n        inputs -- Name of the input raster file. \n        output -- Output shapefile. \n        samples -- Number of sample sites returned. \n        iterations -- Maximum iterations (if stopping criteria not reached). \n        seed -- Seed for RNG consistency. \n        prob -- Probability of random resample or resampling worst strata between [0,1]. \n        threshold -- Objective function values below the theshold stop the resampling iterations. \n        temp -- Initial annealing temperature between [0,1]. \n        temp_decay -- Annealing temperature decay proportion between [0,1]. Reduce temperature by this proportion each annealing cycle. \n        cycle -- Number of iterations before decaying annealing temperature. \n        average -- Weight the continuous objective funtion by the 1/N contributing strata. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--samples={}\".format(samples))\n        args.append(\"--iterations={}\".format(iterations))\n        if seed is not None: args.append(\"--seed='{}'\".format(seed))\n        args.append(\"--prob={}\".format(prob))\n        if threshold is not None: args.append(\"--threshold='{}'\".format(threshold))\n        args.append(\"--temp={}\".format(temp))\n        args.append(\"--temp_decay={}\".format(temp_decay))\n        args.append(\"--cycle={}\".format(cycle))\n        if average: args.append(\"--average\")\n        return self.run_tool('conditioned_latin_hypercube', args, callback) # returns 1 if error\n\n    def cos(self, i, output, callback=None):\n        \"\"\"Returns the cosine (cos) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('cos', args, callback) # returns 1 if error\n\n    def cosh(self, i, output, callback=None):\n        \"\"\"Returns the hyperbolic cosine (cosh) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('cosh', args, callback) # returns 1 if error\n\n    def crispness_index(self, i, output=None, callback=None):\n        \"\"\"Calculates the Crispness Index, which is used to quantify how crisp (or conversely how fuzzy) a probability image is.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Optional output html file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        return self.run_tool('crispness_index', args, callback) # returns 1 if error\n\n    def cross_tabulation(self, input1, input2, output, callback=None):\n        \"\"\"Performs a cross-tabulation on two categorical images.\n\n        Keyword arguments:\n\n        input1 -- Input raster file 1. \n        input2 -- Input raster file 1. \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('cross_tabulation', args, callback) # returns 1 if error\n\n    def cumulative_distribution(self, i, output, callback=None):\n        \"\"\"Converts a raster image to its cumulative distribution function.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('cumulative_distribution', args, callback) # returns 1 if error\n\n    def decrement(self, i, output, callback=None):\n        \"\"\"Decreases the values of each grid cell in an input raster by 1.0 (see also InPlaceSubtract).\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('decrement', args, callback) # returns 1 if error\n\n    def divide(self, input1, input2, output, callback=None):\n        \"\"\"Performs a division operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('divide', args, callback) # returns 1 if error\n\n    def equal_to(self, input1, input2, output, callback=None):\n        \"\"\"Performs a equal-to comparison operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('equal_to', args, callback) # returns 1 if error\n\n    def exp(self, i, output, callback=None):\n        \"\"\"Returns the exponential (base e) of values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('exp', args, callback) # returns 1 if error\n\n    def exp2(self, i, output, callback=None):\n        \"\"\"Returns the exponential (base 2) of values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('exp2', args, callback) # returns 1 if error\n\n    def floor(self, i, output, callback=None):\n        \"\"\"Returns the largest (closest to positive infinity) value that is less than or equal to the values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('floor', args, callback) # returns 1 if error\n\n    def greater_than(self, input1, input2, output, incl_equals=False, callback=None):\n        \"\"\"Performs a greater-than comparison operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        incl_equals -- Perform a greater-than-or-equal-to operation. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        if incl_equals: args.append(\"--incl_equals\")\n        return self.run_tool('greater_than', args, callback) # returns 1 if error\n\n    def image_autocorrelation(self, inputs, output, contiguity=\"Rook\", callback=None):\n        \"\"\"Performs Moran's I analysis on two or more input images.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        contiguity -- Contiguity type. \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--contiguity={}\".format(contiguity))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('image_autocorrelation', args, callback) # returns 1 if error\n\n    def image_correlation(self, inputs, output=None, callback=None):\n        \"\"\"Performs image correlation on two or more input images.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        return self.run_tool('image_correlation', args, callback) # returns 1 if error\n\n    def image_correlation_neighbourhood_analysis(self, input1, input2, output1, output2, filter=11, stat=\"pearson\", callback=None):\n        \"\"\"Performs image correlation on two input images neighbourhood search windows.\n\n        Keyword arguments:\n\n        input1 -- Input raster file. \n        input2 -- Input raster file. \n        output1 -- Output correlation (r-value or rho) raster file. \n        output2 -- Output significance (p-value) raster file. \n        filter -- Size of the filter kernel. \n        stat -- Correlation type; one of 'pearson' (default) and 'spearman'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output1='{}'\".format(output1))\n        args.append(\"--output2='{}'\".format(output2))\n        args.append(\"--filter={}\".format(filter))\n        args.append(\"--stat={}\".format(stat))\n        return self.run_tool('image_correlation_neighbourhood_analysis', args, callback) # returns 1 if error\n\n    def image_regression(self, input1, input2, output, out_residuals=None, standardize=False, scattergram=False, num_samples=1000, callback=None):\n        \"\"\"Performs image regression analysis on two input images.\n\n        Keyword arguments:\n\n        input1 -- Input raster file (independent variable, X). \n        input2 -- Input raster file (dependent variable, Y). \n        output -- Output HTML file for regression summary report. \n        out_residuals -- Output raster regression residual file. \n        standardize -- Optional flag indicating whether to standardize the residuals map. \n        scattergram -- Optional flag indicating whether to output a scattergram. \n        num_samples -- Number of samples used to create scattergram. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        if out_residuals is not None: args.append(\"--out_residuals='{}'\".format(out_residuals))\n        if standardize: args.append(\"--standardize\")\n        if scattergram: args.append(\"--scattergram\")\n        args.append(\"--num_samples={}\".format(num_samples))\n        return self.run_tool('image_regression', args, callback) # returns 1 if error\n\n    def in_place_add(self, input1, input2, callback=None):\n        \"\"\"Performs an in-place addition operation (input1 += input2).\n\n        Keyword arguments:\n\n        input1 -- Input raster file. \n        input2 -- Input raster file or constant value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        return self.run_tool('in_place_add', args, callback) # returns 1 if error\n\n    def in_place_divide(self, input1, input2, callback=None):\n        \"\"\"Performs an in-place division operation (input1 /= input2).\n\n        Keyword arguments:\n\n        input1 -- Input raster file. \n        input2 -- Input raster file or constant value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        return self.run_tool('in_place_divide', args, callback) # returns 1 if error\n\n    def in_place_multiply(self, input1, input2, callback=None):\n        \"\"\"Performs an in-place multiplication operation (input1 *= input2).\n\n        Keyword arguments:\n\n        input1 -- Input raster file. \n        input2 -- Input raster file or constant value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        return self.run_tool('in_place_multiply', args, callback) # returns 1 if error\n\n    def in_place_subtract(self, input1, input2, callback=None):\n        \"\"\"Performs an in-place subtraction operation (input1 -= input2).\n\n        Keyword arguments:\n\n        input1 -- Input raster file. \n        input2 -- Input raster file or constant value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        return self.run_tool('in_place_subtract', args, callback) # returns 1 if error\n\n    def increment(self, i, output, callback=None):\n        \"\"\"Increases the values of each grid cell in an input raster by 1.0. (see also InPlaceAdd).\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('increment', args, callback) # returns 1 if error\n\n    def integer_division(self, input1, input2, output, callback=None):\n        \"\"\"Performs an integer division operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('integer_division', args, callback) # returns 1 if error\n\n    def inverse_principal_component_analysis(self, inputs, report, callback=None):\n        \"\"\"This tool performs an inverse principal component analysis on a series of input component images.\n\n        Keyword arguments:\n\n        inputs -- Name of the input PCA component images. \n        report -- Name of the PCA report file (*.html). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--report='{}'\".format(report))\n        return self.run_tool('inverse_principal_component_analysis', args, callback) # returns 1 if error\n\n    def is_no_data(self, i, output, callback=None):\n        \"\"\"Identifies NoData valued pixels in an image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('is_no_data', args, callback) # returns 1 if error\n\n    def kappa_index(self, input1, input2, output, callback=None):\n        \"\"\"Performs a kappa index of agreement (KIA) analysis on two categorical raster files.\n\n        Keyword arguments:\n\n        input1 -- Input classification raster file. \n        input2 -- Input reference raster file. \n        output -- Output HTML file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('kappa_index', args, callback) # returns 1 if error\n\n    def ks_test_for_normality(self, i, output, num_samples=None, callback=None):\n        \"\"\"Evaluates whether the values in a raster are normally distributed.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output HTML file. \n        num_samples -- Number of samples. Leave blank to use whole image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if num_samples is not None: args.append(\"--num_samples='{}'\".format(num_samples))\n        return self.run_tool('ks_test_for_normality', args, callback) # returns 1 if error\n\n    def less_than(self, input1, input2, output, incl_equals=False, callback=None):\n        \"\"\"Performs a less-than comparison operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        incl_equals -- Perform a less-than-or-equal-to operation. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        if incl_equals: args.append(\"--incl_equals\")\n        return self.run_tool('less_than', args, callback) # returns 1 if error\n\n    def list_unique_values(self, i, field, output, callback=None):\n        \"\"\"Lists the unique values contained in a field within a vector's attribute table.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        field -- Input field name in attribute table. \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field='{}'\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('list_unique_values', args, callback) # returns 1 if error\n\n    def list_unique_values_raster(self, i, callback=None):\n        \"\"\"Lists the unique values contained in a field within a vector's attribute table.\n\n        Keyword arguments:\n\n        i -- Input vector file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('list_unique_values_raster', args, callback) # returns 1 if error\n\n    def ln(self, i, output, callback=None):\n        \"\"\"Returns the natural logarithm of values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('ln', args, callback) # returns 1 if error\n\n    def log10(self, i, output, callback=None):\n        \"\"\"Returns the base-10 logarithm of values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('log10', args, callback) # returns 1 if error\n\n    def log2(self, i, output, callback=None):\n        \"\"\"Returns the base-2 logarithm of values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('log2', args, callback) # returns 1 if error\n\n    def max(self, input1, input2, output, callback=None):\n        \"\"\"Performs a MAX operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('max', args, callback) # returns 1 if error\n\n    def min(self, input1, input2, output, callback=None):\n        \"\"\"Performs a MIN operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('min', args, callback) # returns 1 if error\n\n    def modulo(self, input1, input2, output, callback=None):\n        \"\"\"Performs a modulo operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('modulo', args, callback) # returns 1 if error\n\n    def multiply(self, input1, input2, output, callback=None):\n        \"\"\"Performs a multiplication operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('multiply', args, callback) # returns 1 if error\n\n    def negate(self, i, output, callback=None):\n        \"\"\"Changes the sign of values in a raster or the 0-1 values of a Boolean raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('negate', args, callback) # returns 1 if error\n\n    def not_equal_to(self, input1, input2, output, callback=None):\n        \"\"\"Performs a not-equal-to comparison operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('not_equal_to', args, callback) # returns 1 if error\n\n    def paired_sample_t_test(self, input1, input2, output, num_samples=None, callback=None):\n        \"\"\"Performs a 2-sample K-S test for significant differences on two input rasters.\n\n        Keyword arguments:\n\n        input1 -- First input raster file. \n        input2 -- Second input raster file. \n        output -- Output HTML file. \n        num_samples -- Number of samples. Leave blank to use whole image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        if num_samples is not None: args.append(\"--num_samples='{}'\".format(num_samples))\n        return self.run_tool('paired_sample_t_test', args, callback) # returns 1 if error\n\n    def phi_coefficient(self, input1, input2, output, callback=None):\n        \"\"\"This tool performs a binary classification accuracy assessment.\n\n        Keyword arguments:\n\n        input1 -- Name of the first input raster image file. \n        input2 -- Name of the second input raster image file. \n        output -- Name of the output HTML file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('phi_coefficient', args, callback) # returns 1 if error\n\n    def power(self, input1, input2, output, callback=None):\n        \"\"\"Raises the values in grid cells of one rasters, or a constant value, by values in another raster or constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('power', args, callback) # returns 1 if error\n\n    def principal_component_analysis(self, inputs, output, num_comp=None, standardized=False, callback=None):\n        \"\"\"Performs a principal component analysis (PCA) on a multi-spectral dataset.\n\n        Keyword arguments:\n\n        inputs -- Input raster files. \n        output -- Output HTML report file. \n        num_comp -- Number of component images to output; <= to num. input images. \n        standardized -- Perform standardized PCA?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--inputs='{}'\".format(inputs))\n        args.append(\"--output='{}'\".format(output))\n        if num_comp is not None: args.append(\"--num_comp='{}'\".format(num_comp))\n        if standardized: args.append(\"--standardized\")\n        return self.run_tool('principal_component_analysis', args, callback) # returns 1 if error\n\n    def quantiles(self, i, output, num_quantiles=5, callback=None):\n        \"\"\"Transforms raster values into quantiles.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        num_quantiles -- Number of quantiles. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--num_quantiles={}\".format(num_quantiles))\n        return self.run_tool('quantiles', args, callback) # returns 1 if error\n\n    def random_field(self, base, output, callback=None):\n        \"\"\"Creates an image containing random values.\n\n        Keyword arguments:\n\n        base -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--base='{}'\".format(base))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('random_field', args, callback) # returns 1 if error\n\n    def random_sample(self, base, output, num_samples=1000, callback=None):\n        \"\"\"Creates an image containing randomly located sample grid cells with unique IDs.\n\n        Keyword arguments:\n\n        base -- Input raster file. \n        output -- Output raster file. \n        num_samples -- Number of samples. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--base='{}'\".format(base))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--num_samples={}\".format(num_samples))\n        return self.run_tool('random_sample', args, callback) # returns 1 if error\n\n    def raster_calculator(self, output, statement=\"\", callback=None):\n        \"\"\"Performs a complex mathematical operations on one or more input raster images on a cell-to-cell basis.\n\n        Keyword arguments:\n\n        statement -- Statement e.g. cos(\"raster1\") * 35.0 + \"raster2\". This statement must be a valid Rust statement. \n        output -- Name of the output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--statement={}\".format(statement))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('raster_calculator', args, callback) # returns 1 if error\n\n    def raster_histogram(self, i, output, callback=None):\n        \"\"\"Creates a histogram from raster values.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output HTML file (default name will be based on input file if unspecified). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('raster_histogram', args, callback) # returns 1 if error\n\n    def raster_summary_stats(self, i, callback=None):\n        \"\"\"Measures a rasters min, max, average, standard deviation, num. non-nodata cells, and total.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        return self.run_tool('raster_summary_stats', args, callback) # returns 1 if error\n\n    def reciprocal(self, i, output, callback=None):\n        \"\"\"Returns the reciprocal (i.e. 1 / z) of values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('reciprocal', args, callback) # returns 1 if error\n\n    def rescale_value_range(self, i, output, out_min_val, out_max_val, clip_min=None, clip_max=None, callback=None):\n        \"\"\"Performs a min-max contrast stretch on an input greytone image.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        out_min_val -- New minimum value in output image. \n        out_max_val -- New maximum value in output image. \n        clip_min -- Optional lower tail clip value. \n        clip_max -- Optional upper tail clip value. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--out_min_val='{}'\".format(out_min_val))\n        args.append(\"--out_max_val='{}'\".format(out_max_val))\n        if clip_min is not None: args.append(\"--clip_min='{}'\".format(clip_min))\n        if clip_max is not None: args.append(\"--clip_max='{}'\".format(clip_max))\n        return self.run_tool('rescale_value_range', args, callback) # returns 1 if error\n\n    def root_mean_square_error(self, i, base, callback=None):\n        \"\"\"Calculates the RMSE and other accuracy statistics.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        base -- Input base raster file used for comparison. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--base='{}'\".format(base))\n        return self.run_tool('root_mean_square_error', args, callback) # returns 1 if error\n\n    def round(self, i, output, callback=None):\n        \"\"\"Rounds the values in an input raster to the nearest integer value.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('round', args, callback) # returns 1 if error\n\n    def sin(self, i, output, callback=None):\n        \"\"\"Returns the sine (sin) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('sin', args, callback) # returns 1 if error\n\n    def sinh(self, i, output, callback=None):\n        \"\"\"Returns the hyperbolic sine (sinh) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('sinh', args, callback) # returns 1 if error\n\n    def square(self, i, output, callback=None):\n        \"\"\"Squares the values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('square', args, callback) # returns 1 if error\n\n    def square_root(self, i, output, callback=None):\n        \"\"\"Returns the square root of the values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('square_root', args, callback) # returns 1 if error\n\n    def subtract(self, input1, input2, output, callback=None):\n        \"\"\"Performs a differencing operation on two rasters or a raster and a constant value.\n\n        Keyword arguments:\n\n        input1 -- Input raster file or constant value. \n        input2 -- Input raster file or constant value. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('subtract', args, callback) # returns 1 if error\n\n    def tan(self, i, output, callback=None):\n        \"\"\"Returns the tangent (tan) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('tan', args, callback) # returns 1 if error\n\n    def tanh(self, i, output, callback=None):\n        \"\"\"Returns the hyperbolic tangent (tanh) of each values in a raster.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('tanh', args, callback) # returns 1 if error\n\n    def to_degrees(self, i, output, callback=None):\n        \"\"\"Converts a raster from radians to degrees.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('to_degrees', args, callback) # returns 1 if error\n\n    def to_radians(self, i, output, callback=None):\n        \"\"\"Converts a raster from degrees to radians.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('to_radians', args, callback) # returns 1 if error\n\n    def trend_surface(self, i, output, order=1, callback=None):\n        \"\"\"Estimates the trend surface of an input raster file.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        order -- Polynomial order (1 to 10). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--order={}\".format(order))\n        return self.run_tool('trend_surface', args, callback) # returns 1 if error\n\n    def trend_surface_vector_points(self, i, field, output, cell_size, order=1, callback=None):\n        \"\"\"Estimates a trend surface from vector points.\n\n        Keyword arguments:\n\n        i -- Input vector Points file. \n        field -- Input field name in attribute table. \n        output -- Output raster file. \n        order -- Polynomial order (1 to 10). \n        cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--field='{}'\".format(field))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--order={}\".format(order))\n        args.append(\"--cell_size='{}'\".format(cell_size))\n        return self.run_tool('trend_surface_vector_points', args, callback) # returns 1 if error\n\n    def truncate(self, i, output, num_decimals=None, callback=None):\n        \"\"\"Truncates the values in a raster to the desired number of decimal places.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        num_decimals -- Number of decimals left after truncation (default is zero). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if num_decimals is not None: args.append(\"--num_decimals='{}'\".format(num_decimals))\n        return self.run_tool('truncate', args, callback) # returns 1 if error\n\n    def turning_bands_simulation(self, base, output, range, iterations=1000, callback=None):\n        \"\"\"Creates an image containing random values based on a turning-bands simulation.\n\n        Keyword arguments:\n\n        base -- Input base raster file. \n        output -- Output file. \n        range -- The field's range, in xy-units, related to the extent of spatial autocorrelation. \n        iterations -- The number of iterations. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--base='{}'\".format(base))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--range='{}'\".format(range))\n        args.append(\"--iterations={}\".format(iterations))\n        return self.run_tool('turning_bands_simulation', args, callback) # returns 1 if error\n\n    def two_sample_ks_test(self, input1, input2, output, num_samples=None, callback=None):\n        \"\"\"Performs a 2-sample K-S test for significant differences on two input rasters.\n\n        Keyword arguments:\n\n        input1 -- First input raster file. \n        input2 -- Second input raster file. \n        output -- Output HTML file. \n        num_samples -- Number of samples. Leave blank to use whole image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        if num_samples is not None: args.append(\"--num_samples='{}'\".format(num_samples))\n        return self.run_tool('two_sample_ks_test', args, callback) # returns 1 if error\n\n    def wilcoxon_signed_rank_test(self, input1, input2, output, num_samples=None, callback=None):\n        \"\"\"Performs a 2-sample K-S test for significant differences on two input rasters.\n\n        Keyword arguments:\n\n        input1 -- First input raster file. \n        input2 -- Second input raster file. \n        output -- Output HTML file. \n        num_samples -- Number of samples. Leave blank to use whole image. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        if num_samples is not None: args.append(\"--num_samples='{}'\".format(num_samples))\n        return self.run_tool('wilcoxon_signed_rank_test', args, callback) # returns 1 if error\n\n    def xor(self, input1, input2, output, callback=None):\n        \"\"\"Performs a logical XOR operator on two Boolean raster images.\n\n        Keyword arguments:\n\n        input1 -- Input raster file. \n        input2 -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input1='{}'\".format(input1))\n        args.append(\"--input2='{}'\".format(input2))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('xor', args, callback) # returns 1 if error\n\n    def z_scores(self, i, output, callback=None):\n        \"\"\"Standardizes the values in an input raster by converting to z-scores.\n\n        Keyword arguments:\n\n        i -- Input raster file. \n        output -- Output raster file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        return self.run_tool('z_scores', args, callback) # returns 1 if error\n\n    def zonal_statistics(self, i, features, output=None, stat=\"mean\", out_table=None, callback=None):\n        \"\"\"Extracts descriptive statistics for a group of patches in a raster.\n\n        Keyword arguments:\n\n        i -- Input data raster file. \n        features -- Input feature definition raster file. \n        output -- Output raster file. \n        stat -- Statistic to extract, including 'mean', 'median', 'minimum', 'maximum', 'range', 'standard deviation', and 'total'. \n        out_table -- Output HTML Table file. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--features='{}'\".format(features))\n        if output is not None: args.append(\"--output='{}'\".format(output))\n        args.append(\"--stat={}\".format(stat))\n        if out_table is not None: args.append(\"--out_table='{}'\".format(out_table))\n        return self.run_tool('zonal_statistics', args, callback) # returns 1 if error\n\n    #########################\n    # Precision Agriculture #\n    #########################\n\n    def reconcile_multiple_headers(self, i, region_field, yield_field, output, radius=None, min_yield=None, max_yield=None, mean_tonnage=None, callback=None):\n        \"\"\"This tool adjusts the crop yield values for data sets collected with multiple headers or combines.\n\n        Keyword arguments:\n\n        i -- Name of the input points shapefile. \n        region_field -- Name of the attribute containing region data. \n        yield_field -- Name of the attribute containing yield data. \n        output -- Name of the output points shapefile. \n        radius -- Optional search radius, in metres. Only specify this value if you want to calculate locally normalized yield. \n        min_yield -- Minimum yield value in output. \n        max_yield -- Maximum yield value in output. \n        mean_tonnage -- Use this optional parameter to force the output to have a certain overall average tonnage. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--region_field='{}'\".format(region_field))\n        args.append(\"--yield_field='{}'\".format(yield_field))\n        args.append(\"--output='{}'\".format(output))\n        if radius is not None: args.append(\"--radius='{}'\".format(radius))\n        if min_yield is not None: args.append(\"--min_yield='{}'\".format(min_yield))\n        if max_yield is not None: args.append(\"--max_yield='{}'\".format(max_yield))\n        if mean_tonnage is not None: args.append(\"--mean_tonnage='{}'\".format(mean_tonnage))\n        return self.run_tool('reconcile_multiple_headers', args, callback) # returns 1 if error\n\n    def recreate_pass_lines(self, i, yield_field_name, output_lines, output_points, max_change_in_heading=25.0, ignore_zeros=False, callback=None):\n        \"\"\"This tool can be used to approximate the harvester pass lines from yield points.\n\n        Keyword arguments:\n\n        i -- Name of the input points shapefile. \n        yield_field_name -- Name of the attribute containing yield data. \n        output_lines -- Name of the output pass lines shapefile. \n        output_points -- Name of the output points shapefile. \n        max_change_in_heading -- Max change in heading. \n        ignore_zeros -- Ignore zero-valued yield points?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--yield_field_name='{}'\".format(yield_field_name))\n        args.append(\"--output_lines='{}'\".format(output_lines))\n        args.append(\"--output_points='{}'\".format(output_points))\n        args.append(\"--max_change_in_heading={}\".format(max_change_in_heading))\n        if ignore_zeros: args.append(\"--ignore_zeros\")\n        return self.run_tool('recreate_pass_lines', args, callback) # returns 1 if error\n\n    def remove_field_edge_points(self, i, output, dist=None, max_change_in_heading=25.0, flag_edges=False, callback=None):\n        \"\"\"This tool can be used to remove, or flag, most of the points along the edges from a crop yield data set.\n\n        Keyword arguments:\n\n        i -- Name of the input points shapefile. \n        output -- Name of the output points shapefile. \n        dist -- Average distance between passes, in meters. \n        max_change_in_heading -- Max change in heading. \n        flag_edges -- Don't remove edge points, just flag them in the attribute table?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        if dist is not None: args.append(\"--dist='{}'\".format(dist))\n        args.append(\"--max_change_in_heading={}\".format(max_change_in_heading))\n        if flag_edges: args.append(\"--flag_edges\")\n        return self.run_tool('remove_field_edge_points', args, callback) # returns 1 if error\n\n    def yield_filter(self, i, yield_field, pass_field, output, width=6.096, z_score_threshold=2.5, min_yield=0.0, max_yield=99999.9, callback=None):\n        \"\"\"Filters crop yield values of point data derived from combine harvester yield monitors.\n\n        Keyword arguments:\n\n        i -- Name of the input points shapefile. \n        yield_field -- Name of the attribute containing yield data. \n        pass_field -- Name of the attribute containing pass line ID. \n        output -- Name of the output points shapefile. \n        width -- Pass swath width (m). \n        z_score_threshold -- Z-score threshold value (default=2.5). \n        min_yield -- Minimum yield value in output. \n        max_yield -- Maximum yield value in output. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--yield_field='{}'\".format(yield_field))\n        args.append(\"--pass_field='{}'\".format(pass_field))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--width={}\".format(width))\n        args.append(\"--z_score_threshold={}\".format(z_score_threshold))\n        args.append(\"--min_yield={}\".format(min_yield))\n        args.append(\"--max_yield={}\".format(max_yield))\n        return self.run_tool('yield_filter', args, callback) # returns 1 if error\n\n    def yield_map(self, i, pass_field_name, output, width=6.096, max_change_in_heading=25.0, callback=None):\n        \"\"\"This tool can be used to create a segmented-vector polygon yield map from a set of harvester points.\n\n        Keyword arguments:\n\n        i -- Name of the input points shapefile. \n        pass_field_name -- Name of the attribute containing pass line ID. \n        output -- Name of the output polygon shapefile. \n        width -- Pass swath width (m). \n        max_change_in_heading -- Max change in heading. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--pass_field_name='{}'\".format(pass_field_name))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--width={}\".format(width))\n        args.append(\"--max_change_in_heading={}\".format(max_change_in_heading))\n        return self.run_tool('yield_map', args, callback) # returns 1 if error\n\n    def yield_normalization(self, i, yield_field, output, standardize=False, radius=None, min_yield=0.0, max_yield=99999.9, callback=None):\n        \"\"\"This tool can be used to normalize the yield points for a field.\n\n        Keyword arguments:\n\n        i -- Name of the input points shapefile. \n        yield_field -- Name of the attribute containing yield data. \n        output -- Name of the output points shapefile. \n        standardize -- Should the yield values be standardized (converted to z-scores) rather than normalized?. \n        radius -- Optional search radius, in metres. Only specify this value if you want to calculate locally normalized yield. \n        min_yield -- Minimum yield value in output. \n        max_yield -- Maximum yield value in output. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--yield_field='{}'\".format(yield_field))\n        args.append(\"--output='{}'\".format(output))\n        if standardize: args.append(\"--standardize\")\n        if radius is not None: args.append(\"--radius='{}'\".format(radius))\n        args.append(\"--min_yield={}\".format(min_yield))\n        args.append(\"--max_yield={}\".format(max_yield))\n        return self.run_tool('yield_normalization', args, callback) # returns 1 if error\n\n    ###########################\n    # Stream Network Analysis #\n    ###########################\n\n    def distance_to_outlet(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Calculates the distance of stream grid cells to the channel network outlet cell.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('distance_to_outlet', args, callback) # returns 1 if error\n\n    def extract_streams(self, flow_accum, output, threshold, zero_background=False, callback=None):\n        \"\"\"Extracts stream grid cells from a flow accumulation raster.\n\n        Keyword arguments:\n\n        flow_accum -- Input raster D8 flow accumulation file. \n        output -- Output raster file. \n        threshold -- Threshold in flow accumulation values for channelization. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--flow_accum='{}'\".format(flow_accum))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--threshold='{}'\".format(threshold))\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('extract_streams', args, callback) # returns 1 if error\n\n    def extract_valleys(self, dem, output, variant=\"LQ\", line_thin=True, filter=5, callback=None):\n        \"\"\"Identifies potential valley bottom grid cells based on local topolography alone.\n\n        Keyword arguments:\n\n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        variant -- Options include 'LQ' (lower quartile), 'JandR' (Johnston and Rosenfeld), and 'PandD' (Peucker and Douglas); default is 'LQ'. \n        line_thin -- Optional flag indicating whether post-processing line-thinning should be performed. \n        filter -- Optional argument (only used when variant='lq') providing the filter size, in grid cells, used for lq-filtering (default is 5). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--variant={}\".format(variant))\n        if line_thin: args.append(\"--line_thin\")\n        args.append(\"--filter={}\".format(filter))\n        return self.run_tool('extract_valleys', args, callback) # returns 1 if error\n\n    def farthest_channel_head(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Calculates the distance to the furthest upstream channel head for each stream cell.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('farthest_channel_head', args, callback) # returns 1 if error\n\n    def find_main_stem(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Finds the main stem, based on stream lengths, of each stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('find_main_stem', args, callback) # returns 1 if error\n\n    def hack_stream_order(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Assigns the Hack stream order to each tributary in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('hack_stream_order', args, callback) # returns 1 if error\n\n    def horton_stream_order(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Assigns the Horton stream order to each tributary in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('horton_stream_order', args, callback) # returns 1 if error\n\n    def length_of_upstream_channels(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Calculates the total length of channels upstream.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('length_of_upstream_channels', args, callback) # returns 1 if error\n\n    def long_profile(self, d8_pntr, streams, dem, output, esri_pntr=False, callback=None):\n        \"\"\"Plots the stream longitudinal profiles for one or more rivers.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        dem -- Input raster DEM file. \n        output -- Output HTML file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('long_profile', args, callback) # returns 1 if error\n\n    def long_profile_from_points(self, d8_pntr, points, dem, output, esri_pntr=False, callback=None):\n        \"\"\"Plots the longitudinal profiles from flow-paths initiating from a set of vector points.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        points -- Input vector points file. \n        dem -- Input raster DEM file. \n        output -- Output HTML file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--points='{}'\".format(points))\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('long_profile_from_points', args, callback) # returns 1 if error\n\n    def raster_streams_to_vector(self, streams, d8_pntr, output, esri_pntr=False, callback=None):\n        \"\"\"Converts a raster stream file into a vector file.\n\n        Keyword arguments:\n\n        streams -- Input raster streams file. \n        d8_pntr -- Input raster D8 pointer file. \n        output -- Output vector file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('raster_streams_to_vector', args, callback) # returns 1 if error\n\n    def rasterize_streams(self, streams, base, output, nodata=True, feature_id=False, callback=None):\n        \"\"\"Rasterizes vector streams based on Lindsay (2016) method.\n\n        Keyword arguments:\n\n        streams -- Input vector streams file. \n        base -- Input base raster file. \n        output -- Output raster file. \n        nodata -- Use NoData value for background?. \n        feature_id -- Use feature number as output value?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--base='{}'\".format(base))\n        args.append(\"--output='{}'\".format(output))\n        if nodata: args.append(\"--nodata\")\n        if feature_id: args.append(\"--feature_id\")\n        return self.run_tool('rasterize_streams', args, callback) # returns 1 if error\n\n    def remove_short_streams(self, d8_pntr, streams, output, min_length, esri_pntr=False, callback=None):\n        \"\"\"Removes short first-order streams from a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        min_length -- Minimum tributary length (in map units) used for network pruning. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--min_length='{}'\".format(min_length))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        return self.run_tool('remove_short_streams', args, callback) # returns 1 if error\n\n    def repair_stream_vector_topology(self, i, output, dist=\"\", callback=None):\n        \"\"\"This tool resolves topological errors and inconsistencies associated with digitized vector streams.\n\n        Keyword arguments:\n\n        i -- Name of the input lines vector file. \n        output -- Name of the output lines vector file. \n        dist -- Snap distance, in xy units (metres). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--input='{}'\".format(i))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--dist={}\".format(dist))\n        return self.run_tool('repair_stream_vector_topology', args, callback) # returns 1 if error\n\n    def shreve_stream_magnitude(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Assigns the Shreve stream magnitude to each link in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('shreve_stream_magnitude', args, callback) # returns 1 if error\n\n    def strahler_stream_order(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Assigns the Strahler stream order to each link in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('strahler_stream_order', args, callback) # returns 1 if error\n\n    def stream_link_class(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Identifies the exterior/interior links and nodes in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('stream_link_class', args, callback) # returns 1 if error\n\n    def stream_link_identifier(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Assigns a unique identifier to each link in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('stream_link_identifier', args, callback) # returns 1 if error\n\n    def stream_link_length(self, d8_pntr, linkid, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Estimates the length of each link (or tributary) in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        linkid -- Input raster streams link ID (or tributary ID) file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--linkid='{}'\".format(linkid))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('stream_link_length', args, callback) # returns 1 if error\n\n    def stream_link_slope(self, d8_pntr, linkid, dem, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Estimates the average slope of each link (or tributary) in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        linkid -- Input raster streams link ID (or tributary ID) file. \n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--linkid='{}'\".format(linkid))\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('stream_link_slope', args, callback) # returns 1 if error\n\n    def stream_slope_continuous(self, d8_pntr, streams, dem, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Estimates the slope of each grid cell in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        dem -- Input raster DEM file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('stream_slope_continuous', args, callback) # returns 1 if error\n\n    def topological_stream_order(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Assigns each link in a stream network its topological order.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('topological_stream_order', args, callback) # returns 1 if error\n\n    def tributary_identifier(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None):\n        \"\"\"Assigns a unique identifier to each tributary in a stream network.\n\n        Keyword arguments:\n\n        d8_pntr -- Input raster D8 pointer file. \n        streams -- Input raster streams file. \n        output -- Output raster file. \n        esri_pntr -- D8 pointer uses the ESRI style scheme. \n        zero_background -- Flag indicating whether a background value of zero should be used. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--d8_pntr='{}'\".format(d8_pntr))\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--output='{}'\".format(output))\n        if esri_pntr: args.append(\"--esri_pntr\")\n        if zero_background: args.append(\"--zero_background\")\n        return self.run_tool('tributary_identifier', args, callback) # returns 1 if error\n\n    def vector_stream_network_analysis(self, streams, dem, output, cutting_height=10.0, snap=0.1, callback=None):\n        \"\"\"This tool performs common stream network analysis operations on an input vector stream file.\n\n        Keyword arguments:\n\n        streams -- Name of the input streams vector file. \n        dem -- Name of the input DEM raster file. \n        output -- Name of the output lines shapefile. \n        cutting_height -- Maximum ridge-cutting height (z units). \n        snap -- Snap distance, in xy units (metres). \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--streams='{}'\".format(streams))\n        args.append(\"--dem='{}'\".format(dem))\n        args.append(\"--output='{}'\".format(output))\n        args.append(\"--cutting_height={}\".format(cutting_height))\n        args.append(\"--snap={}\".format(snap))\n        return self.run_tool('vector_stream_network_analysis', args, callback) # returns 1 if error\n\n    ######################\n    # Whitebox Utilities #\n    ######################\n\n    def install_wb_extension(self, install_extension=\"General Toolset Extension\", callback=None):\n        \"\"\"Use to install a Whitebox extension product.\n\n        Keyword arguments:\n\n        install_extension -- Name of the extension product to install. Options include: 'General Toolset Extension', 'DEM & Spatial Hydrology Extension', 'Lidar & Remote Sensing Extension', and 'Agriculture Extension'. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        args.append(\"--install_extension={}\".format(install_extension))\n        return self.run_tool('install_wb_extension', args, callback) # returns 1 if error\n\n    def launch_wb_runner(self, clear_app_state=False, callback=None):\n        \"\"\"Opens the Whitebox Runner application.\n\n        Keyword arguments:\n\n        clear_app_state -- Clear the application state memory?. \n        callback -- Custom function for handling tool text outputs.\n        \"\"\"\n        args = []\n        if clear_app_state: args.append(\"--clear_app_state\")\n        return self.run_tool('launch_wb_runner', args, callback) # returns 1 if error\n"
  },
  {
    "path": "WhiteboxTools.pyt",
    "content": "import arcpy\nimport os, sys\nimport webbrowser\nfrom WBT.whitebox_tools import WhiteboxTools\nif sys.version_info < (3, 0):\n    from StringIO import StringIO\nelse:\n    from io import StringIO\n\nwbt = WhiteboxTools()\ntool_labels = []\n\ntool_labels.append(\"Absolute Value\")\ntool_labels.append(\"Accumulation Curvature\")\ntool_labels.append(\"Adaptive Filter\")\ntool_labels.append(\"Add\")\ntool_labels.append(\"Add Point Coordinates To Table\")\ntool_labels.append(\"Aggregate Raster\")\ntool_labels.append(\"And\")\ntool_labels.append(\"Anova\")\ntool_labels.append(\"Arc Cos\")\ntool_labels.append(\"Arc Sin\")\ntool_labels.append(\"Arc Tan\")\ntool_labels.append(\"Arcosh\")\ntool_labels.append(\"Arsinh\")\ntool_labels.append(\"Artanh\")\ntool_labels.append(\"Ascii To Las\")\ntool_labels.append(\"Aspect\")\ntool_labels.append(\"Assess Route\")\ntool_labels.append(\"Atan2\")\ntool_labels.append(\"Attribute Correlation\")\ntool_labels.append(\"Attribute Correlation Neighbourhood Analysis\")\ntool_labels.append(\"Attribute Histogram\")\ntool_labels.append(\"Attribute Scattergram\")\ntool_labels.append(\"Average Flowpath Slope\")\ntool_labels.append(\"Average Normal Vector Angular Deviation\")\ntool_labels.append(\"Average Overlay\")\ntool_labels.append(\"Average Upslope Flowpath Length\")\ntool_labels.append(\"Balance Contrast Enhancement\")\ntool_labels.append(\"Basins\")\ntool_labels.append(\"Bilateral Filter\")\ntool_labels.append(\"Block Maximum Gridding\")\ntool_labels.append(\"Block Minimum Gridding\")\ntool_labels.append(\"Boundary Shape Complexity\")\ntool_labels.append(\"Breach Depressions\")\ntool_labels.append(\"Breach Depressions Least Cost\")\ntool_labels.append(\"Breach Single Cell Pits\")\ntool_labels.append(\"Breakline Mapping\")\ntool_labels.append(\"Buffer Raster\")\ntool_labels.append(\"Burn Streams At Roads\")\ntool_labels.append(\"Canny Edge Detection\")\ntool_labels.append(\"Ceil\")\ntool_labels.append(\"Centroid\")\ntool_labels.append(\"Centroid Vector\")\ntool_labels.append(\"Change Vector Analysis\")\ntool_labels.append(\"Circular Variance Of Aspect\")\ntool_labels.append(\"Classify Buildings In Lidar\")\ntool_labels.append(\"Classify Lidar\")\ntool_labels.append(\"Classify Overlap Points\")\ntool_labels.append(\"Clean Vector\")\ntool_labels.append(\"Clip\")\ntool_labels.append(\"Clip Lidar To Polygon\")\ntool_labels.append(\"Clip Raster To Polygon\")\ntool_labels.append(\"Closing\")\ntool_labels.append(\"Clump\")\ntool_labels.append(\"Colourize Based On Class\")\ntool_labels.append(\"Colourize Based On Point Returns\")\ntool_labels.append(\"Compactness Ratio\")\ntool_labels.append(\"Conditional Evaluation\")\ntool_labels.append(\"Conditioned Latin Hypercube\")\ntool_labels.append(\"Conservative Smoothing Filter\")\ntool_labels.append(\"Construct Vector Tin\")\ntool_labels.append(\"Contours From Points\")\ntool_labels.append(\"Contours From Raster\")\ntool_labels.append(\"Convert Nodata To Zero\")\ntool_labels.append(\"Convert Raster Format\")\ntool_labels.append(\"Corner Detection\")\ntool_labels.append(\"Correct Vignetting\")\ntool_labels.append(\"Cos\")\ntool_labels.append(\"Cosh\")\ntool_labels.append(\"Cost Allocation\")\ntool_labels.append(\"Cost Distance\")\ntool_labels.append(\"Cost Pathway\")\ntool_labels.append(\"Count If\")\ntool_labels.append(\"Create Colour Composite\")\ntool_labels.append(\"Create Hexagonal Vector Grid\")\ntool_labels.append(\"Create Plane\")\ntool_labels.append(\"Create Rectangular Vector Grid\")\ntool_labels.append(\"Crispness Index\")\ntool_labels.append(\"Cross Tabulation\")\ntool_labels.append(\"Csv Points To Vector\")\ntool_labels.append(\"Cumulative Distribution\")\ntool_labels.append(\"Curvedness\")\ntool_labels.append(\"D Inf Flow Accumulation\")\ntool_labels.append(\"D Inf Mass Flux\")\ntool_labels.append(\"D Inf Pointer\")\ntool_labels.append(\"D8 Flow Accumulation\")\ntool_labels.append(\"D8 Mass Flux\")\ntool_labels.append(\"D8 Pointer\")\ntool_labels.append(\"Dbscan\")\ntool_labels.append(\"Decrement\")\ntool_labels.append(\"Dem Void Filling\")\ntool_labels.append(\"Depth In Sink\")\ntool_labels.append(\"Depth To Water\")\ntool_labels.append(\"Dev From Mean Elev\")\ntool_labels.append(\"Diff From Mean Elev\")\ntool_labels.append(\"Diff Of Gaussian Filter\")\ntool_labels.append(\"Difference\")\ntool_labels.append(\"Difference Curvature\")\ntool_labels.append(\"Direct Decorrelation Stretch\")\ntool_labels.append(\"Directional Relief\")\ntool_labels.append(\"Dissolve\")\ntool_labels.append(\"Distance To Outlet\")\ntool_labels.append(\"Diversity Filter\")\ntool_labels.append(\"Divide\")\ntool_labels.append(\"Downslope Distance To Stream\")\ntool_labels.append(\"Downslope Flowpath Length\")\ntool_labels.append(\"Downslope Index\")\ntool_labels.append(\"Edge Contamination\")\ntool_labels.append(\"Edge Density\")\ntool_labels.append(\"Edge Preserving Mean Filter\")\ntool_labels.append(\"Edge Proportion\")\ntool_labels.append(\"Elev Above Pit\")\ntool_labels.append(\"Elev Percentile\")\ntool_labels.append(\"Elev Relative To Min Max\")\ntool_labels.append(\"Elev Relative To Watershed Min Max\")\ntool_labels.append(\"Elevation Above Stream\")\ntool_labels.append(\"Elevation Above Stream Euclidean\")\ntool_labels.append(\"Eliminate Coincident Points\")\ntool_labels.append(\"Elongation Ratio\")\ntool_labels.append(\"Embankment Mapping\")\ntool_labels.append(\"Emboss Filter\")\ntool_labels.append(\"Equal To\")\ntool_labels.append(\"Erase\")\ntool_labels.append(\"Erase Polygon From Lidar\")\ntool_labels.append(\"Erase Polygon From Raster\")\ntool_labels.append(\"Euclidean Allocation\")\ntool_labels.append(\"Euclidean Distance\")\ntool_labels.append(\"Evaluate Training Sites\")\ntool_labels.append(\"Exp\")\ntool_labels.append(\"Exp2\")\ntool_labels.append(\"Export Table To Csv\")\ntool_labels.append(\"Exposure Towards Wind Flux\")\ntool_labels.append(\"Extend Vector Lines\")\ntool_labels.append(\"Extract Nodes\")\ntool_labels.append(\"Extract Raster Values At Points\")\ntool_labels.append(\"Extract Streams\")\ntool_labels.append(\"Extract Valleys\")\ntool_labels.append(\"Farthest Channel Head\")\ntool_labels.append(\"Fast Almost Gaussian Filter\")\ntool_labels.append(\"Fd8 Flow Accumulation\")\ntool_labels.append(\"Fd8 Pointer\")\ntool_labels.append(\"Feature Preserving Smoothing\")\ntool_labels.append(\"Fetch Analysis\")\ntool_labels.append(\"Fill Burn\")\ntool_labels.append(\"Fill Depressions\")\ntool_labels.append(\"Fill Depressions Planchon And Darboux\")\ntool_labels.append(\"Fill Depressions Wang And Liu\")\ntool_labels.append(\"Fill Missing Data\")\ntool_labels.append(\"Fill Single Cell Pits\")\ntool_labels.append(\"Filter Lidar\")\ntool_labels.append(\"Filter Lidar Classes\")\ntool_labels.append(\"Filter Lidar Scan Angles\")\ntool_labels.append(\"Filter Raster Features By Area\")\ntool_labels.append(\"Find Flightline Edge Points\")\ntool_labels.append(\"Find Lowest Or Highest Points\")\ntool_labels.append(\"Find Main Stem\")\ntool_labels.append(\"Find No Flow Cells\")\ntool_labels.append(\"Find Parallel Flow\")\ntool_labels.append(\"Find Patch Or Class Edge Cells\")\ntool_labels.append(\"Find Ridges\")\ntool_labels.append(\"Fix Dangling Arcs\")\ntool_labels.append(\"Flatten Lakes\")\ntool_labels.append(\"Flightline Overlap\")\ntool_labels.append(\"Flip Image\")\ntool_labels.append(\"Flood Order\")\ntool_labels.append(\"Floor\")\ntool_labels.append(\"Flow Accumulation Full Workflow\")\ntool_labels.append(\"Flow Length Diff\")\ntool_labels.append(\"Gamma Correction\")\ntool_labels.append(\"Gaussian Contrast Stretch\")\ntool_labels.append(\"Gaussian Curvature\")\ntool_labels.append(\"Gaussian Filter\")\ntool_labels.append(\"Gaussian Scale Space\")\ntool_labels.append(\"Generalize Classified Raster\")\ntool_labels.append(\"Generalize With Similarity\")\ntool_labels.append(\"Generating Function\")\ntool_labels.append(\"Geomorphons\")\ntool_labels.append(\"Greater Than\")\ntool_labels.append(\"Hack Stream Order\")\ntool_labels.append(\"Heat Map\")\ntool_labels.append(\"Height Above Ground\")\ntool_labels.append(\"High Pass Bilateral Filter\")\ntool_labels.append(\"High Pass Filter\")\ntool_labels.append(\"High Pass Median Filter\")\ntool_labels.append(\"Highest Position\")\ntool_labels.append(\"Hillshade\")\ntool_labels.append(\"Hillslopes\")\ntool_labels.append(\"Histogram Equalization\")\ntool_labels.append(\"Histogram Matching\")\ntool_labels.append(\"Histogram Matching Two Images\")\ntool_labels.append(\"Hole Proportion\")\ntool_labels.append(\"Horizon Angle\")\ntool_labels.append(\"Horizontal Excess Curvature\")\ntool_labels.append(\"Horton Stream Order\")\ntool_labels.append(\"Hydrologic Connectivity\")\ntool_labels.append(\"Hypsometric Analysis\")\ntool_labels.append(\"Hypsometrically Tinted Hillshade\")\ntool_labels.append(\"Idw Interpolation\")\ntool_labels.append(\"Ihs To Rgb\")\ntool_labels.append(\"Image Autocorrelation\")\ntool_labels.append(\"Image Correlation\")\ntool_labels.append(\"Image Correlation Neighbourhood Analysis\")\ntool_labels.append(\"Image Regression\")\ntool_labels.append(\"Image Segmentation\")\ntool_labels.append(\"Image Slider\")\ntool_labels.append(\"Image Stack Profile\")\ntool_labels.append(\"Impoundment Size Index\")\ntool_labels.append(\"In Place Add\")\ntool_labels.append(\"In Place Divide\")\ntool_labels.append(\"In Place Multiply\")\ntool_labels.append(\"In Place Subtract\")\ntool_labels.append(\"Increment\")\ntool_labels.append(\"Individual Tree Detection\")\ntool_labels.append(\"Insert Dams\")\ntool_labels.append(\"Install Wb Extension\")\ntool_labels.append(\"Integer Division\")\ntool_labels.append(\"Integral Image\")\ntool_labels.append(\"Intersect\")\ntool_labels.append(\"Inverse Pca\")\ntool_labels.append(\"Is No Data\")\ntool_labels.append(\"Isobasins\")\ntool_labels.append(\"Jenson Snap Pour Points\")\ntool_labels.append(\"Join Tables\")\ntool_labels.append(\"K Means Clustering\")\ntool_labels.append(\"K Nearest Mean Filter\")\ntool_labels.append(\"Kappa Index\")\ntool_labels.append(\"Knn Classification\")\ntool_labels.append(\"Knn Regression\")\ntool_labels.append(\"Ks Test For Normality\")\ntool_labels.append(\"Laplacian Filter\")\ntool_labels.append(\"Laplacian Of Gaussian Filter\")\ntool_labels.append(\"Las To Ascii\")\ntool_labels.append(\"Las To Laz\")\ntool_labels.append(\"Las To Multipoint Shapefile\")\ntool_labels.append(\"Las To Shapefile\")\ntool_labels.append(\"Las To Zlidar\")\ntool_labels.append(\"Launch Wb Runner\")\ntool_labels.append(\"Layer Footprint\")\ntool_labels.append(\"Laz To Las\")\ntool_labels.append(\"Lee Sigma Filter\")\ntool_labels.append(\"Length Of Upstream Channels\")\ntool_labels.append(\"Less Than\")\ntool_labels.append(\"Lidar Block Maximum\")\ntool_labels.append(\"Lidar Block Minimum\")\ntool_labels.append(\"Lidar Classify Subset\")\ntool_labels.append(\"Lidar Colourize\")\ntool_labels.append(\"Lidar Contour\")\ntool_labels.append(\"Lidar Digital Surface Model\")\ntool_labels.append(\"Lidar Eigenvalue Features\")\ntool_labels.append(\"Lidar Elevation Slice\")\ntool_labels.append(\"Lidar Ground Point Filter\")\ntool_labels.append(\"Lidar Hex Binning\")\ntool_labels.append(\"Lidar Hillshade\")\ntool_labels.append(\"Lidar Histogram\")\ntool_labels.append(\"Lidar Idw Interpolation\")\ntool_labels.append(\"Lidar Info\")\ntool_labels.append(\"Lidar Join\")\ntool_labels.append(\"Lidar Kappa Index\")\ntool_labels.append(\"Lidar Nearest Neighbour Gridding\")\ntool_labels.append(\"Lidar Point Density\")\ntool_labels.append(\"Lidar Point Return Analysis\")\ntool_labels.append(\"Lidar Point Stats\")\ntool_labels.append(\"Lidar Ransac Planes\")\ntool_labels.append(\"Lidar Rbf Interpolation\")\ntool_labels.append(\"Lidar Remove Duplicates\")\ntool_labels.append(\"Lidar Remove Outliers\")\ntool_labels.append(\"Lidar Rooftop Analysis\")\ntool_labels.append(\"Lidar Segmentation\")\ntool_labels.append(\"Lidar Segmentation Based Filter\")\ntool_labels.append(\"Lidar Shift\")\ntool_labels.append(\"Lidar Sibson Interpolation\")\ntool_labels.append(\"Lidar Thin\")\ntool_labels.append(\"Lidar Thin High Density\")\ntool_labels.append(\"Lidar Tile\")\ntool_labels.append(\"Lidar Tile Footprint\")\ntool_labels.append(\"Lidar Tin Gridding\")\ntool_labels.append(\"Lidar Tophat Transform\")\ntool_labels.append(\"Line Detection Filter\")\ntool_labels.append(\"Line Intersections\")\ntool_labels.append(\"Line Thinning\")\ntool_labels.append(\"Linearity Index\")\ntool_labels.append(\"Lines To Polygons\")\ntool_labels.append(\"List Unique Values\")\ntool_labels.append(\"List Unique Values Raster\")\ntool_labels.append(\"Ln\")\ntool_labels.append(\"Local Hypsometric Analysis\")\ntool_labels.append(\"Local Quadratic Regression\")\ntool_labels.append(\"Log10\")\ntool_labels.append(\"Log2\")\ntool_labels.append(\"Logistic Regression\")\ntool_labels.append(\"Long Profile\")\ntool_labels.append(\"Long Profile From Points\")\ntool_labels.append(\"Longest Flowpath\")\ntool_labels.append(\"Low Points On Headwater Divides\")\ntool_labels.append(\"Lowest Position\")\ntool_labels.append(\"Majority Filter\")\ntool_labels.append(\"Map Off Terrain Objects\")\ntool_labels.append(\"Max\")\ntool_labels.append(\"Max Absolute Overlay\")\ntool_labels.append(\"Max Anisotropy Dev\")\ntool_labels.append(\"Max Anisotropy Dev Signature\")\ntool_labels.append(\"Max Branch Length\")\ntool_labels.append(\"Max Difference From Mean\")\ntool_labels.append(\"Max Downslope Elev Change\")\ntool_labels.append(\"Max Elev Dev Signature\")\ntool_labels.append(\"Max Elevation Deviation\")\ntool_labels.append(\"Max Overlay\")\ntool_labels.append(\"Max Upslope Elev Change\")\ntool_labels.append(\"Max Upslope Flowpath Length\")\ntool_labels.append(\"Max Upslope Value\")\ntool_labels.append(\"Maximal Curvature\")\ntool_labels.append(\"Maximum Filter\")\ntool_labels.append(\"Md Inf Flow Accumulation\")\ntool_labels.append(\"Mean Curvature\")\ntool_labels.append(\"Mean Filter\")\ntool_labels.append(\"Median Filter\")\ntool_labels.append(\"Medoid\")\ntool_labels.append(\"Merge Line Segments\")\ntool_labels.append(\"Merge Table With Csv\")\ntool_labels.append(\"Merge Vectors\")\ntool_labels.append(\"Min\")\ntool_labels.append(\"Min Absolute Overlay\")\ntool_labels.append(\"Min Dist Classification\")\ntool_labels.append(\"Min Downslope Elev Change\")\ntool_labels.append(\"Min Max Contrast Stretch\")\ntool_labels.append(\"Min Overlay\")\ntool_labels.append(\"Minimal Curvature\")\ntool_labels.append(\"Minimum Bounding Box\")\ntool_labels.append(\"Minimum Bounding Circle\")\ntool_labels.append(\"Minimum Bounding Envelope\")\ntool_labels.append(\"Minimum Convex Hull\")\ntool_labels.append(\"Minimum Filter\")\ntool_labels.append(\"Modified K Means Clustering\")\ntool_labels.append(\"Modify Lidar\")\ntool_labels.append(\"Modify No Data Value\")\ntool_labels.append(\"Modulo\")\ntool_labels.append(\"Mosaic\")\ntool_labels.append(\"Mosaic With Feathering\")\ntool_labels.append(\"Multi Part To Single Part\")\ntool_labels.append(\"Multidirectional Hillshade\")\ntool_labels.append(\"Multiply\")\ntool_labels.append(\"Multiply Overlay\")\ntool_labels.append(\"Multiscale Curvatures\")\ntool_labels.append(\"Multiscale Elevation Percentile\")\ntool_labels.append(\"Multiscale Roughness\")\ntool_labels.append(\"Multiscale Roughness Signature\")\ntool_labels.append(\"Multiscale Std Dev Normals\")\ntool_labels.append(\"Multiscale Std Dev Normals Signature\")\ntool_labels.append(\"Multiscale Topographic Position Image\")\ntool_labels.append(\"Narrowness Index\")\ntool_labels.append(\"Natural Neighbour Interpolation\")\ntool_labels.append(\"Nearest Neighbour Gridding\")\ntool_labels.append(\"Negate\")\ntool_labels.append(\"New Raster From Base\")\ntool_labels.append(\"Normal Vectors\")\ntool_labels.append(\"Normalize Lidar\")\ntool_labels.append(\"Normalized Difference Index\")\ntool_labels.append(\"Not\")\ntool_labels.append(\"Not Equal To\")\ntool_labels.append(\"Num Downslope Neighbours\")\ntool_labels.append(\"Num Inflowing Neighbours\")\ntool_labels.append(\"Num Upslope Neighbours\")\ntool_labels.append(\"Olympic Filter\")\ntool_labels.append(\"Opening\")\ntool_labels.append(\"Openness\")\ntool_labels.append(\"Or\")\ntool_labels.append(\"Paired Sample T Test\")\ntool_labels.append(\"Panchromatic Sharpening\")\ntool_labels.append(\"Parallelepiped Classification\")\ntool_labels.append(\"Patch Orientation\")\ntool_labels.append(\"Pennock Landform Class\")\ntool_labels.append(\"Percent Elev Range\")\ntool_labels.append(\"Percent Equal To\")\ntool_labels.append(\"Percent Greater Than\")\ntool_labels.append(\"Percent Less Than\")\ntool_labels.append(\"Percentage Contrast Stretch\")\ntool_labels.append(\"Percentile Filter\")\ntool_labels.append(\"Perimeter Area Ratio\")\ntool_labels.append(\"Phi Coefficient\")\ntool_labels.append(\"Pick From List\")\ntool_labels.append(\"Piecewise Contrast Stretch\")\ntool_labels.append(\"Plan Curvature\")\ntool_labels.append(\"Polygon Area\")\ntool_labels.append(\"Polygon Long Axis\")\ntool_labels.append(\"Polygon Perimeter\")\ntool_labels.append(\"Polygon Short Axis\")\ntool_labels.append(\"Polygonize\")\ntool_labels.append(\"Polygons To Lines\")\ntool_labels.append(\"Power\")\ntool_labels.append(\"Prewitt Filter\")\ntool_labels.append(\"Principal Component Analysis\")\ntool_labels.append(\"Print Geo Tiff Tags\")\ntool_labels.append(\"Profile\")\ntool_labels.append(\"Profile Curvature\")\ntool_labels.append(\"Qin Flow Accumulation\")\ntool_labels.append(\"Quantiles\")\ntool_labels.append(\"Quinn Flow Accumulation\")\ntool_labels.append(\"Radial Basis Function Interpolation\")\ntool_labels.append(\"Radius Of Gyration\")\ntool_labels.append(\"Raise Walls\")\ntool_labels.append(\"Random Field\")\ntool_labels.append(\"Random Forest Classification\")\ntool_labels.append(\"Random Forest Regression\")\ntool_labels.append(\"Random Sample\")\ntool_labels.append(\"Range Filter\")\ntool_labels.append(\"Raster Area\")\ntool_labels.append(\"Raster Calculator\")\ntool_labels.append(\"Raster Cell Assignment\")\ntool_labels.append(\"Raster Histogram\")\ntool_labels.append(\"Raster Perimeter\")\ntool_labels.append(\"Raster Streams To Vector\")\ntool_labels.append(\"Raster Summary Stats\")\ntool_labels.append(\"Raster To Vector Lines\")\ntool_labels.append(\"Raster To Vector Points\")\ntool_labels.append(\"Raster To Vector Polygons\")\ntool_labels.append(\"Rasterize Streams\")\ntool_labels.append(\"Reciprocal\")\ntool_labels.append(\"Reclass\")\ntool_labels.append(\"Reclass Equal Interval\")\ntool_labels.append(\"Reclass From File\")\ntool_labels.append(\"Reconcile Multiple Headers\")\ntool_labels.append(\"Recover Flightline Info\")\ntool_labels.append(\"Recreate Pass Lines\")\ntool_labels.append(\"Reinitialize Attribute Table\")\ntool_labels.append(\"Related Circumscribing Circle\")\ntool_labels.append(\"Relative Aspect\")\ntool_labels.append(\"Relative Topographic Position\")\ntool_labels.append(\"Remove Field Edge Points\")\ntool_labels.append(\"Remove Off Terrain Objects\")\ntool_labels.append(\"Remove Polygon Holes\")\ntool_labels.append(\"Remove Raster Polygon Holes\")\ntool_labels.append(\"Remove Short Streams\")\ntool_labels.append(\"Remove Spurs\")\ntool_labels.append(\"Repair Stream Vector Topology\")\ntool_labels.append(\"Resample\")\ntool_labels.append(\"Rescale Value Range\")\ntool_labels.append(\"Rgb To Ihs\")\ntool_labels.append(\"Rho8 Flow Accumulation\")\ntool_labels.append(\"Rho8 Pointer\")\ntool_labels.append(\"Ring Curvature\")\ntool_labels.append(\"River Centerlines\")\ntool_labels.append(\"Roberts Cross Filter\")\ntool_labels.append(\"Root Mean Square Error\")\ntool_labels.append(\"Rotor\")\ntool_labels.append(\"Round\")\ntool_labels.append(\"Ruggedness Index\")\ntool_labels.append(\"Scharr Filter\")\ntool_labels.append(\"Sediment Transport Index\")\ntool_labels.append(\"Select Tiles By Polygon\")\ntool_labels.append(\"Set Nodata Value\")\ntool_labels.append(\"Shadow Animation\")\ntool_labels.append(\"Shadow Image\")\ntool_labels.append(\"Shape Complexity Index\")\ntool_labels.append(\"Shape Complexity Index Raster\")\ntool_labels.append(\"Shape Index\")\ntool_labels.append(\"Shreve Stream Magnitude\")\ntool_labels.append(\"Sigmoidal Contrast Stretch\")\ntool_labels.append(\"Sin\")\ntool_labels.append(\"Single Part To Multi Part\")\ntool_labels.append(\"Sinh\")\ntool_labels.append(\"Sink\")\ntool_labels.append(\"Slope\")\ntool_labels.append(\"Slope Vs Aspect Plot\")\ntool_labels.append(\"Slope Vs Elevation Plot\")\ntool_labels.append(\"Smooth Vectors\")\ntool_labels.append(\"Smooth Vegetation Residual\")\ntool_labels.append(\"Snap Pour Points\")\ntool_labels.append(\"Sobel Filter\")\ntool_labels.append(\"Sort Lidar\")\ntool_labels.append(\"Spherical Std Dev Of Normals\")\ntool_labels.append(\"Split Colour Composite\")\ntool_labels.append(\"Split Lidar\")\ntool_labels.append(\"Split Vector Lines\")\ntool_labels.append(\"Split With Lines\")\ntool_labels.append(\"Square\")\ntool_labels.append(\"Square Root\")\ntool_labels.append(\"Standard Deviation Contrast Stretch\")\ntool_labels.append(\"Standard Deviation Filter\")\ntool_labels.append(\"Standard Deviation Of Slope\")\ntool_labels.append(\"Stochastic Depression Analysis\")\ntool_labels.append(\"Strahler Order Basins\")\ntool_labels.append(\"Strahler Stream Order\")\ntool_labels.append(\"Stream Link Class\")\ntool_labels.append(\"Stream Link Identifier\")\ntool_labels.append(\"Stream Link Length\")\ntool_labels.append(\"Stream Link Slope\")\ntool_labels.append(\"Stream Power Index\")\ntool_labels.append(\"Stream Slope Continuous\")\ntool_labels.append(\"Subbasins\")\ntool_labels.append(\"Subtract\")\ntool_labels.append(\"Sum Overlay\")\ntool_labels.append(\"Surface Area Ratio\")\ntool_labels.append(\"Svm Classification\")\ntool_labels.append(\"Svm Regression\")\ntool_labels.append(\"Symmetrical Difference\")\ntool_labels.append(\"Tan\")\ntool_labels.append(\"Tangential Curvature\")\ntool_labels.append(\"Tanh\")\ntool_labels.append(\"Thicken Raster Line\")\ntool_labels.append(\"Time In Daylight\")\ntool_labels.append(\"Tin Gridding\")\ntool_labels.append(\"To Degrees\")\ntool_labels.append(\"To Radians\")\ntool_labels.append(\"Tophat Transform\")\ntool_labels.append(\"Topo Render\")\ntool_labels.append(\"Topographic Position Animation\")\ntool_labels.append(\"Topological Stream Order\")\ntool_labels.append(\"Total Curvature\")\ntool_labels.append(\"Total Filter\")\ntool_labels.append(\"Trace Downslope Flowpaths\")\ntool_labels.append(\"Travelling Salesman Problem\")\ntool_labels.append(\"Trend Surface\")\ntool_labels.append(\"Trend Surface Vector Points\")\ntool_labels.append(\"Tributary Identifier\")\ntool_labels.append(\"Truncate\")\ntool_labels.append(\"Turning Bands Simulation\")\ntool_labels.append(\"Two Sample Ks Test\")\ntool_labels.append(\"Union\")\ntool_labels.append(\"Unnest Basins\")\ntool_labels.append(\"Unsharp Masking\")\ntool_labels.append(\"Unsphericity\")\ntool_labels.append(\"Update Nodata Cells\")\ntool_labels.append(\"Upslope Depression Storage\")\ntool_labels.append(\"User Defined Weights Filter\")\ntool_labels.append(\"Vector Hex Binning\")\ntool_labels.append(\"Vector Lines To Raster\")\ntool_labels.append(\"Vector Points To Raster\")\ntool_labels.append(\"Vector Polygons To Raster\")\ntool_labels.append(\"Vector Stream Network Analysis\")\ntool_labels.append(\"Vertical Excess Curvature\")\ntool_labels.append(\"Viewshed\")\ntool_labels.append(\"Visibility Index\")\ntool_labels.append(\"Voronoi Diagram\")\ntool_labels.append(\"Watershed\")\ntool_labels.append(\"Weighted Overlay\")\ntool_labels.append(\"Weighted Sum\")\ntool_labels.append(\"Wetness Index\")\ntool_labels.append(\"Wilcoxon Signed Rank Test\")\ntool_labels.append(\"Write Function Memory Insertion\")\ntool_labels.append(\"Xor\")\ntool_labels.append(\"Yield Filter\")\ntool_labels.append(\"Yield Map\")\ntool_labels.append(\"Yield Normalization\")\ntool_labels.append(\"Z Scores\")\ntool_labels.append(\"Zlidar To Las\")\ntool_labels.append(\"Zonal Statistics\")\n\n\nclass Toolbox(object):\n    def __init__(self):\n        \"\"\"Define the toolbox (the name of the toolbox is the name of the .pyt file).\"\"\"\n        self.label = \"WhiteboxTools Toolbox\"\n        self.alias = \"WBT\"\n\n        # List of tool classes associated with this toolbox\n        tools = []        \n        tools.append(Help)\n        tools.append(License)\n        tools.append(Version)\n        tools.append(ListTools)\n        tools.append(ToolHelp)\n        tools.append(ToolParameters)\n        tools.append(ViewCode)\n        tools.append(RunTool)\n\n        tools.append(AbsoluteValue)\n        tools.append(AccumulationCurvature)\n        tools.append(AdaptiveFilter)\n        tools.append(Add)\n        tools.append(AddPointCoordinatesToTable)\n        tools.append(AggregateRaster)\n        tools.append(And)\n        tools.append(Anova)\n        tools.append(ArcCos)\n        tools.append(ArcSin)\n        tools.append(ArcTan)\n        tools.append(Arcosh)\n        tools.append(Arsinh)\n        tools.append(Artanh)\n        tools.append(AsciiToLas)\n        tools.append(Aspect)\n        tools.append(AssessRoute)\n        tools.append(Atan2)\n        tools.append(AttributeCorrelation)\n        tools.append(AttributeCorrelationNeighbourhoodAnalysis)\n        tools.append(AttributeHistogram)\n        tools.append(AttributeScattergram)\n        tools.append(AverageFlowpathSlope)\n        tools.append(AverageNormalVectorAngularDeviation)\n        tools.append(AverageOverlay)\n        tools.append(AverageUpslopeFlowpathLength)\n        tools.append(BalanceContrastEnhancement)\n        tools.append(Basins)\n        tools.append(BilateralFilter)\n        tools.append(BlockMaximumGridding)\n        tools.append(BlockMinimumGridding)\n        tools.append(BoundaryShapeComplexity)\n        tools.append(BreachDepressions)\n        tools.append(BreachDepressionsLeastCost)\n        tools.append(BreachSingleCellPits)\n        tools.append(BreaklineMapping)\n        tools.append(BufferRaster)\n        tools.append(BurnStreamsAtRoads)\n        tools.append(CannyEdgeDetection)\n        tools.append(Ceil)\n        tools.append(Centroid)\n        tools.append(CentroidVector)\n        tools.append(ChangeVectorAnalysis)\n        tools.append(CircularVarianceOfAspect)\n        tools.append(ClassifyBuildingsInLidar)\n        tools.append(ClassifyLidar)\n        tools.append(ClassifyOverlapPoints)\n        tools.append(CleanVector)\n        tools.append(Clip)\n        tools.append(ClipLidarToPolygon)\n        tools.append(ClipRasterToPolygon)\n        tools.append(Closing)\n        tools.append(Clump)\n        tools.append(ColourizeBasedOnClass)\n        tools.append(ColourizeBasedOnPointReturns)\n        tools.append(CompactnessRatio)\n        tools.append(ConditionalEvaluation)\n        tools.append(ConditionedLatinHypercube)\n        tools.append(ConservativeSmoothingFilter)\n        tools.append(ConstructVectorTin)\n        tools.append(ContoursFromPoints)\n        tools.append(ContoursFromRaster)\n        tools.append(ConvertNodataToZero)\n        tools.append(ConvertRasterFormat)\n        tools.append(CornerDetection)\n        tools.append(CorrectVignetting)\n        tools.append(Cos)\n        tools.append(Cosh)\n        tools.append(CostAllocation)\n        tools.append(CostDistance)\n        tools.append(CostPathway)\n        tools.append(CountIf)\n        tools.append(CreateColourComposite)\n        tools.append(CreateHexagonalVectorGrid)\n        tools.append(CreatePlane)\n        tools.append(CreateRectangularVectorGrid)\n        tools.append(CrispnessIndex)\n        tools.append(CrossTabulation)\n        tools.append(CsvPointsToVector)\n        tools.append(CumulativeDistribution)\n        tools.append(Curvedness)\n        tools.append(D8FlowAccumulation)\n        tools.append(D8MassFlux)\n        tools.append(D8Pointer)\n        tools.append(DInfFlowAccumulation)\n        tools.append(DInfMassFlux)\n        tools.append(DInfPointer)\n        tools.append(Dbscan)\n        tools.append(Decrement)\n        tools.append(DemVoidFilling)\n        tools.append(DepthInSink)\n        tools.append(DepthToWater)\n        tools.append(DevFromMeanElev)\n        tools.append(DiffFromMeanElev)\n        tools.append(DiffOfGaussianFilter)\n        tools.append(Difference)\n        tools.append(DifferenceCurvature)\n        tools.append(DirectDecorrelationStretch)\n        tools.append(DirectionalRelief)\n        tools.append(Dissolve)\n        tools.append(DistanceToOutlet)\n        tools.append(DiversityFilter)\n        tools.append(Divide)\n        tools.append(DownslopeDistanceToStream)\n        tools.append(DownslopeFlowpathLength)\n        tools.append(DownslopeIndex)\n        tools.append(EdgeContamination)\n        tools.append(EdgeDensity)\n        tools.append(EdgePreservingMeanFilter)\n        tools.append(EdgeProportion)\n        tools.append(ElevAbovePit)\n        tools.append(ElevPercentile)\n        tools.append(ElevRelativeToMinMax)\n        tools.append(ElevRelativeToWatershedMinMax)\n        tools.append(ElevationAboveStream)\n        tools.append(ElevationAboveStreamEuclidean)\n        tools.append(EliminateCoincidentPoints)\n        tools.append(ElongationRatio)\n        tools.append(EmbankmentMapping)\n        tools.append(EmbossFilter)\n        tools.append(EqualTo)\n        tools.append(Erase)\n        tools.append(ErasePolygonFromLidar)\n        tools.append(ErasePolygonFromRaster)\n        tools.append(EuclideanAllocation)\n        tools.append(EuclideanDistance)\n        tools.append(EvaluateTrainingSites)\n        tools.append(Exp)\n        tools.append(Exp2)\n        tools.append(ExportTableToCsv)\n        tools.append(ExposureTowardsWindFlux)\n        tools.append(ExtendVectorLines)\n        tools.append(ExtractNodes)\n        tools.append(ExtractRasterValuesAtPoints)\n        tools.append(ExtractStreams)\n        tools.append(ExtractValleys)\n        tools.append(Fd8FlowAccumulation)\n        tools.append(Fd8Pointer)\n        tools.append(FarthestChannelHead)\n        tools.append(FastAlmostGaussianFilter)\n        tools.append(FeaturePreservingSmoothing)\n        tools.append(FetchAnalysis)\n        tools.append(FillBurn)\n        tools.append(FillDepressions)\n        tools.append(FillDepressionsPlanchonAndDarboux)\n        tools.append(FillDepressionsWangAndLiu)\n        tools.append(FillMissingData)\n        tools.append(FillSingleCellPits)\n        tools.append(FilterLidar)\n        tools.append(FilterLidarClasses)\n        tools.append(FilterLidarScanAngles)\n        tools.append(FilterRasterFeaturesByArea)\n        tools.append(FindFlightlineEdgePoints)\n        tools.append(FindLowestOrHighestPoints)\n        tools.append(FindMainStem)\n        tools.append(FindNoFlowCells)\n        tools.append(FindParallelFlow)\n        tools.append(FindPatchOrClassEdgeCells)\n        tools.append(FindRidges)\n        tools.append(FixDanglingArcs)\n        tools.append(FlattenLakes)\n        tools.append(FlightlineOverlap)\n        tools.append(FlipImage)\n        tools.append(FloodOrder)\n        tools.append(Floor)\n        tools.append(FlowAccumulationFullWorkflow)\n        tools.append(FlowLengthDiff)\n        tools.append(GammaCorrection)\n        tools.append(GaussianContrastStretch)\n        tools.append(GaussianCurvature)\n        tools.append(GaussianFilter)\n        tools.append(GaussianScaleSpace)\n        tools.append(GeneralizeClassifiedRaster)\n        tools.append(GeneralizeWithSimilarity)\n        tools.append(GeneratingFunction)\n        tools.append(Geomorphons)\n        tools.append(GreaterThan)\n        tools.append(HackStreamOrder)\n        tools.append(HeatMap)\n        tools.append(HeightAboveGround)\n        tools.append(HighPassBilateralFilter)\n        tools.append(HighPassFilter)\n        tools.append(HighPassMedianFilter)\n        tools.append(HighestPosition)\n        tools.append(Hillshade)\n        tools.append(Hillslopes)\n        tools.append(HistogramEqualization)\n        tools.append(HistogramMatching)\n        tools.append(HistogramMatchingTwoImages)\n        tools.append(HoleProportion)\n        tools.append(HorizonAngle)\n        tools.append(HorizontalExcessCurvature)\n        tools.append(HortonStreamOrder)\n        tools.append(HydrologicConnectivity)\n        tools.append(HypsometricAnalysis)\n        tools.append(HypsometricallyTintedHillshade)\n        tools.append(IdwInterpolation)\n        tools.append(IhsToRgb)\n        tools.append(ImageAutocorrelation)\n        tools.append(ImageCorrelation)\n        tools.append(ImageCorrelationNeighbourhoodAnalysis)\n        tools.append(ImageRegression)\n        tools.append(ImageSegmentation)\n        tools.append(ImageSlider)\n        tools.append(ImageStackProfile)\n        tools.append(ImpoundmentSizeIndex)\n        tools.append(InPlaceAdd)\n        tools.append(InPlaceDivide)\n        tools.append(InPlaceMultiply)\n        tools.append(InPlaceSubtract)\n        tools.append(Increment)\n        tools.append(IndividualTreeDetection)\n        tools.append(InsertDams)\n        tools.append(InstallWbExtension)\n        tools.append(IntegerDivision)\n        tools.append(IntegralImage)\n        tools.append(Intersect)\n        tools.append(InversePrincipalComponentAnalysis)\n        tools.append(IsNoData)\n        tools.append(Isobasins)\n        tools.append(JensonSnapPourPoints)\n        tools.append(JoinTables)\n        tools.append(KMeansClustering)\n        tools.append(KNearestMeanFilter)\n        tools.append(KappaIndex)\n        tools.append(KnnClassification)\n        tools.append(KnnRegression)\n        tools.append(KsTestForNormality)\n        tools.append(LaplacianFilter)\n        tools.append(LaplacianOfGaussianFilter)\n        tools.append(LasToAscii)\n        tools.append(LasToLaz)\n        tools.append(LasToMultipointShapefile)\n        tools.append(LasToShapefile)\n        tools.append(LasToZlidar)\n        tools.append(LaunchWbRunner)\n        tools.append(LayerFootprint)\n        tools.append(LazToLas)\n        tools.append(LeeSigmaFilter)\n        tools.append(LengthOfUpstreamChannels)\n        tools.append(LessThan)\n        tools.append(LidarBlockMaximum)\n        tools.append(LidarBlockMinimum)\n        tools.append(LidarClassifySubset)\n        tools.append(LidarColourize)\n        tools.append(LidarContour)\n        tools.append(LidarDigitalSurfaceModel)\n        tools.append(LidarEigenvalueFeatures)\n        tools.append(LidarElevationSlice)\n        tools.append(LidarGroundPointFilter)\n        tools.append(LidarHexBinning)\n        tools.append(LidarHillshade)\n        tools.append(LidarHistogram)\n        tools.append(LidarIdwInterpolation)\n        tools.append(LidarInfo)\n        tools.append(LidarJoin)\n        tools.append(LidarKappaIndex)\n        tools.append(LidarNearestNeighbourGridding)\n        tools.append(LidarPointDensity)\n        tools.append(LidarPointReturnAnalysis)\n        tools.append(LidarPointStats)\n        tools.append(LidarRansacPlanes)\n        tools.append(LidarRbfInterpolation)\n        tools.append(LidarRemoveDuplicates)\n        tools.append(LidarRemoveOutliers)\n        tools.append(LidarRooftopAnalysis)\n        tools.append(LidarSegmentation)\n        tools.append(LidarSegmentationBasedFilter)\n        tools.append(LidarShift)\n        tools.append(LidarSibsonInterpolation)\n        tools.append(LidarTinGridding)\n        tools.append(LidarThin)\n        tools.append(LidarThinHighDensity)\n        tools.append(LidarTile)\n        tools.append(LidarTileFootprint)\n        tools.append(LidarTophatTransform)\n        tools.append(LineDetectionFilter)\n        tools.append(LineIntersections)\n        tools.append(LineThinning)\n        tools.append(LinearityIndex)\n        tools.append(LinesToPolygons)\n        tools.append(ListUniqueValues)\n        tools.append(ListUniqueValuesRaster)\n        tools.append(Ln)\n        tools.append(LocalHypsometricAnalysis)\n        tools.append(LocalQuadraticRegression)\n        tools.append(Log10)\n        tools.append(Log2)\n        tools.append(LogisticRegression)\n        tools.append(LongProfile)\n        tools.append(LongProfileFromPoints)\n        tools.append(LongestFlowpath)\n        tools.append(LowPointsOnHeadwaterDivides)\n        tools.append(LowestPosition)\n        tools.append(MdInfFlowAccumulation)\n        tools.append(MajorityFilter)\n        tools.append(MapOffTerrainObjects)\n        tools.append(Max)\n        tools.append(MaxAbsoluteOverlay)\n        tools.append(MaxAnisotropyDev)\n        tools.append(MaxAnisotropyDevSignature)\n        tools.append(MaxBranchLength)\n        tools.append(MaxDifferenceFromMean)\n        tools.append(MaxDownslopeElevChange)\n        tools.append(MaxElevDevSignature)\n        tools.append(MaxElevationDeviation)\n        tools.append(MaxOverlay)\n        tools.append(MaxUpslopeElevChange)\n        tools.append(MaxUpslopeFlowpathLength)\n        tools.append(MaxUpslopeValue)\n        tools.append(MaximalCurvature)\n        tools.append(MaximumFilter)\n        tools.append(MeanCurvature)\n        tools.append(MeanFilter)\n        tools.append(MedianFilter)\n        tools.append(Medoid)\n        tools.append(MergeLineSegments)\n        tools.append(MergeTableWithCsv)\n        tools.append(MergeVectors)\n        tools.append(Min)\n        tools.append(MinAbsoluteOverlay)\n        tools.append(MinDistClassification)\n        tools.append(MinDownslopeElevChange)\n        tools.append(MinMaxContrastStretch)\n        tools.append(MinOverlay)\n        tools.append(MinimalCurvature)\n        tools.append(MinimumBoundingBox)\n        tools.append(MinimumBoundingCircle)\n        tools.append(MinimumBoundingEnvelope)\n        tools.append(MinimumConvexHull)\n        tools.append(MinimumFilter)\n        tools.append(ModifiedKMeansClustering)\n        tools.append(ModifyLidar)\n        tools.append(ModifyNoDataValue)\n        tools.append(Modulo)\n        tools.append(Mosaic)\n        tools.append(MosaicWithFeathering)\n        tools.append(MultiPartToSinglePart)\n        tools.append(MultidirectionalHillshade)\n        tools.append(Multiply)\n        tools.append(MultiplyOverlay)\n        tools.append(MultiscaleCurvatures)\n        tools.append(MultiscaleElevationPercentile)\n        tools.append(MultiscaleRoughness)\n        tools.append(MultiscaleRoughnessSignature)\n        tools.append(MultiscaleStdDevNormals)\n        tools.append(MultiscaleStdDevNormalsSignature)\n        tools.append(MultiscaleTopographicPositionImage)\n        tools.append(NarrownessIndex)\n        tools.append(NaturalNeighbourInterpolation)\n        tools.append(NearestNeighbourGridding)\n        tools.append(Negate)\n        tools.append(NewRasterFromBase)\n        tools.append(NormalVectors)\n        tools.append(NormalizeLidar)\n        tools.append(NormalizedDifferenceIndex)\n        tools.append(Not)\n        tools.append(NotEqualTo)\n        tools.append(NumDownslopeNeighbours)\n        tools.append(NumInflowingNeighbours)\n        tools.append(NumUpslopeNeighbours)\n        tools.append(OlympicFilter)\n        tools.append(Opening)\n        tools.append(Openness)\n        tools.append(Or)\n        tools.append(PairedSampleTTest)\n        tools.append(PanchromaticSharpening)\n        tools.append(ParallelepipedClassification)\n        tools.append(PatchOrientation)\n        tools.append(PennockLandformClass)\n        tools.append(PercentElevRange)\n        tools.append(PercentEqualTo)\n        tools.append(PercentGreaterThan)\n        tools.append(PercentLessThan)\n        tools.append(PercentageContrastStretch)\n        tools.append(PercentileFilter)\n        tools.append(PerimeterAreaRatio)\n        tools.append(PhiCoefficient)\n        tools.append(PickFromList)\n        tools.append(PiecewiseContrastStretch)\n        tools.append(PlanCurvature)\n        tools.append(PolygonArea)\n        tools.append(PolygonLongAxis)\n        tools.append(PolygonPerimeter)\n        tools.append(PolygonShortAxis)\n        tools.append(Polygonize)\n        tools.append(PolygonsToLines)\n        tools.append(Power)\n        tools.append(PrewittFilter)\n        tools.append(PrincipalComponentAnalysis)\n        tools.append(PrintGeoTiffTags)\n        tools.append(Profile)\n        tools.append(ProfileCurvature)\n        tools.append(QinFlowAccumulation)\n        tools.append(Quantiles)\n        tools.append(QuinnFlowAccumulation)\n        tools.append(RadialBasisFunctionInterpolation)\n        tools.append(RadiusOfGyration)\n        tools.append(RaiseWalls)\n        tools.append(RandomField)\n        tools.append(RandomForestClassification)\n        tools.append(RandomForestRegression)\n        tools.append(RandomSample)\n        tools.append(RangeFilter)\n        tools.append(RasterArea)\n        tools.append(RasterCalculator)\n        tools.append(RasterCellAssignment)\n        tools.append(RasterHistogram)\n        tools.append(RasterPerimeter)\n        tools.append(RasterStreamsToVector)\n        tools.append(RasterSummaryStats)\n        tools.append(RasterToVectorLines)\n        tools.append(RasterToVectorPoints)\n        tools.append(RasterToVectorPolygons)\n        tools.append(RasterizeStreams)\n        tools.append(Reciprocal)\n        tools.append(Reclass)\n        tools.append(ReclassEqualInterval)\n        tools.append(ReclassFromFile)\n        tools.append(ReconcileMultipleHeaders)\n        tools.append(RecoverFlightlineInfo)\n        tools.append(RecreatePassLines)\n        tools.append(ReinitializeAttributeTable)\n        tools.append(RelatedCircumscribingCircle)\n        tools.append(RelativeAspect)\n        tools.append(RelativeTopographicPosition)\n        tools.append(RemoveFieldEdgePoints)\n        tools.append(RemoveOffTerrainObjects)\n        tools.append(RemovePolygonHoles)\n        tools.append(RemoveRasterPolygonHoles)\n        tools.append(RemoveShortStreams)\n        tools.append(RemoveSpurs)\n        tools.append(RepairStreamVectorTopology)\n        tools.append(Resample)\n        tools.append(RescaleValueRange)\n        tools.append(RgbToIhs)\n        tools.append(Rho8FlowAccumulation)\n        tools.append(Rho8Pointer)\n        tools.append(RingCurvature)\n        tools.append(RiverCenterlines)\n        tools.append(RobertsCrossFilter)\n        tools.append(RootMeanSquareError)\n        tools.append(Rotor)\n        tools.append(Round)\n        tools.append(RuggednessIndex)\n        tools.append(ScharrFilter)\n        tools.append(SedimentTransportIndex)\n        tools.append(SelectTilesByPolygon)\n        tools.append(SetNodataValue)\n        tools.append(ShadowAnimation)\n        tools.append(ShadowImage)\n        tools.append(ShapeComplexityIndex)\n        tools.append(ShapeComplexityIndexRaster)\n        tools.append(ShapeIndex)\n        tools.append(ShreveStreamMagnitude)\n        tools.append(SigmoidalContrastStretch)\n        tools.append(Sin)\n        tools.append(SinglePartToMultiPart)\n        tools.append(Sinh)\n        tools.append(Sink)\n        tools.append(Slope)\n        tools.append(SlopeVsAspectPlot)\n        tools.append(SlopeVsElevationPlot)\n        tools.append(SmoothVectors)\n        tools.append(SmoothVegetationResidual)\n        tools.append(SnapPourPoints)\n        tools.append(SobelFilter)\n        tools.append(SortLidar)\n        tools.append(SphericalStdDevOfNormals)\n        tools.append(SplitColourComposite)\n        tools.append(SplitLidar)\n        tools.append(SplitVectorLines)\n        tools.append(SplitWithLines)\n        tools.append(Square)\n        tools.append(SquareRoot)\n        tools.append(StandardDeviationContrastStretch)\n        tools.append(StandardDeviationFilter)\n        tools.append(StandardDeviationOfSlope)\n        tools.append(StochasticDepressionAnalysis)\n        tools.append(StrahlerOrderBasins)\n        tools.append(StrahlerStreamOrder)\n        tools.append(StreamLinkClass)\n        tools.append(StreamLinkIdentifier)\n        tools.append(StreamLinkLength)\n        tools.append(StreamLinkSlope)\n        tools.append(StreamPowerIndex)\n        tools.append(StreamSlopeContinuous)\n        tools.append(Subbasins)\n        tools.append(Subtract)\n        tools.append(SumOverlay)\n        tools.append(SurfaceAreaRatio)\n        tools.append(SvmClassification)\n        tools.append(SvmRegression)\n        tools.append(SymmetricalDifference)\n        tools.append(TinGridding)\n        tools.append(Tan)\n        tools.append(TangentialCurvature)\n        tools.append(Tanh)\n        tools.append(ThickenRasterLine)\n        tools.append(TimeInDaylight)\n        tools.append(ToDegrees)\n        tools.append(ToRadians)\n        tools.append(TophatTransform)\n        tools.append(TopoRender)\n        tools.append(TopographicPositionAnimation)\n        tools.append(TopologicalStreamOrder)\n        tools.append(TotalCurvature)\n        tools.append(TotalFilter)\n        tools.append(TraceDownslopeFlowpaths)\n        tools.append(TravellingSalesmanProblem)\n        tools.append(TrendSurface)\n        tools.append(TrendSurfaceVectorPoints)\n        tools.append(TributaryIdentifier)\n        tools.append(Truncate)\n        tools.append(TurningBandsSimulation)\n        tools.append(TwoSampleKsTest)\n        tools.append(Union)\n        tools.append(UnnestBasins)\n        tools.append(UnsharpMasking)\n        tools.append(Unsphericity)\n        tools.append(UpdateNodataCells)\n        tools.append(UpslopeDepressionStorage)\n        tools.append(UserDefinedWeightsFilter)\n        tools.append(VectorHexBinning)\n        tools.append(VectorLinesToRaster)\n        tools.append(VectorPointsToRaster)\n        tools.append(VectorPolygonsToRaster)\n        tools.append(VectorStreamNetworkAnalysis)\n        tools.append(VerticalExcessCurvature)\n        tools.append(Viewshed)\n        tools.append(VisibilityIndex)\n        tools.append(VoronoiDiagram)\n        tools.append(Watershed)\n        tools.append(WeightedOverlay)\n        tools.append(WeightedSum)\n        tools.append(WetnessIndex)\n        tools.append(WilcoxonSignedRankTest)\n        tools.append(WriteFunctionMemoryInsertion)\n        tools.append(Xor)\n        tools.append(YieldFilter)\n        tools.append(YieldMap)\n        tools.append(YieldNormalization)\n        tools.append(ZScores)\n        tools.append(ZlidarToLas)\n        tools.append(ZonalStatistics)\n\n        self.tools = tools\n\n\nclass Help(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"Help\"\n        self.description = \"Help description for WhiteboxTools\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        params = None\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        messages.addMessage(wbt.help())\n        return\n\n\nclass License(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"License\"\n        self.description = \"License information for WhiteboxTools.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        params = None\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        messages.addMessage(wbt.license())\n        return\n\n\nclass Version(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"Version\"\n        self.description = \"Version information for WhiteboxTools.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        params = None\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        messages.addMessage(wbt.version())\n        return\n\n\nclass ListTools(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"List Tools\"\n        self.description = \"All available tools in WhiteboxTools.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n\n        # First parameter\n        param0 = arcpy.Parameter(\n            displayName=\"Keywords\",\n            name=\"keywords\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        # param0.multiValue = True\n        param0.value = \"lidar\"\n        params = [param0]\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        param0 = parameters[0].valueAsText\n\n        if param0 is None:\n            tools = wbt.list_tools()\n        else:\n            tools = wbt.list_tools([param0])\n            \n        for index, tool in enumerate(sorted(tools)):\n            messages.addMessage(\"{}. {}: {}\".format(index + 1, tool, tools[tool]))\n        return\n\n\nclass ToolHelp(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"Tool Help\"\n        self.description = \"Help description for a specific tool.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        tool_name = arcpy.Parameter(\n            displayName=\"Select a tool\",\n            name=\"tool_name\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        tool_name.value = \"Lidar Info\"\n        tool_name.filter.type = \"ValueList\"\n        tool_name.filter.list = tool_labels\n\n        params = [tool_name]\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        param0 = parameters[0].valueAsText\n        tool_name = param0.replace(\" \", \"\").strip()\n        messages.addMessage(wbt.tool_help(tool_name))\n        return\n\n\nclass ToolParameters(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"Tool Parameters\"\n        self.description = \"Tool parameter descriptions for a specific tool.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        tool_name = arcpy.Parameter(\n            displayName=\"Select a tool\",\n            name=\"tool_name\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        tool_name.value = \"Lidar Info\"\n        tool_name.filter.type = \"ValueList\"\n        tool_name.filter.list = tool_labels\n\n        params = [tool_name]\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        param0 = parameters[0].valueAsText\n        tool_name = param0.replace(\" \", \"\").strip()\n        messages.addMessage(wbt.tool_parameters(tool_name))\n        return\n\n\nclass ViewCode(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"View Code\"\n        self.description = \"Source code for a specific tool.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        tool_name = arcpy.Parameter(\n            displayName=\"Select a tool\",\n            name=\"tool_name\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        tool_name.value = \"Lidar Info\"\n        tool_name.filter.type = \"ValueList\"\n        tool_name.filter.list = tool_labels\n\n        params = [tool_name]\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        \"\"\"The source code of the tool.\"\"\"\n        param0 = parameters[0].valueAsText\n        tool_name = param0.replace(\" \", \"\").strip()        \n        messages.addMessage(\"Opening default browser...\")\n        webbrowser.get('windows-default').open(wbt.view_code(tool_name))\n        messages.addMessage(wbt.view_code(tool_name))\n        return\n\n\nclass RunTool(object):\n    def __init__(self):\n        \"\"\"Define the tool (tool name is the name of the class).\"\"\"\n        self.label = \"Run Tool\"\n        self.description = \"Runs a tool and specifies tool arguments.\"\n        self.category = \"About WhiteboxTools\"\n        self.canRunInBackground = False\n\n    def getParameterInfo(self):\n        \"\"\"Define parameter definitions\"\"\"\n        tool_name = arcpy.Parameter(\n            displayName=\"Select a tool\",\n            name=\"tool_name\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        tool_name.value = \"Breach Depressions\"\n        tool_name.filter.type = \"ValueList\"\n        tool_name.filter.list = tool_labels\n\n        args = arcpy.Parameter(\n            displayName=\"Arguments\",\n            name=\"agrs\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        args.value = '--dem=\"/path/to/DEM.tif\"  --output=\"/path/to/output.tif\"'\n\n        params = [tool_name, args]\n        return params\n\n    def isLicensed(self):\n        \"\"\"Set whether tool is licensed to execute.\"\"\"\n        return True\n\n    def updateParameters(self, parameters):\n        \"\"\"Modify the values and properties of parameters before internal\n        validation is performed.  This method is called whenever a parameter\n        has been changed.\"\"\"\n        return\n\n    def updateMessages(self, parameters):\n        \"\"\"Modify the messages created by internal validation for each tool\n        parameter.  This method is called after internal validation.\"\"\"\n        return\n\n    def execute(self, parameters, messages):\n        param0 = parameters[0].valueAsText\n        args = parameters[1].valueAsText\n        tool_name = param0.replace(\" \", \"\").strip()\n        dir_path = os.path.dirname(os.path.realpath(__file__))    \n        exe_path = os.path.join(dir_path, \"WBT/whitebox_tools.exe\")\n        cmd = '{} --run={} {}'.format(exe_path, tool_name, args)\n        if \"-v\" not in cmd:\n            cmd = cmd + ' -v'  \n        messages.addMessage(cmd)  \n        messages.addMessage(os.popen(cmd).read().rstrip())\n        return\n\n\nclass AbsoluteValue(object):\n    def __init__(self):\n        self.label = \"Absolute Value\"\n        self.description = \"Calculates the absolute value of every cell in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.absolute_value(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AccumulationCurvature(object):\n    def __init__(self):\n        self.label = \"Accumulation Curvature\"\n        self.description = \"This tool calculates accumulation curvature from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.accumulation_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AdaptiveFilter(object):\n    def __init__(self):\n        self.label = \"Adaptive Filter\"\n        self.description = \"Performs an adaptive filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Difference From Mean Threshold (# Std. Dev.)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        threshold.value = '2.0'\n\n        params = [i, output, filterx, filtery, threshold]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        threshold = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.adaptive_filter(i=i, output=output, filterx=filterx, filtery=filtery, threshold=threshold)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Add(object):\n    def __init__(self):\n        self.label = \"Add\"\n        self.description = \"Performs an addition operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.add(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AddPointCoordinatesToTable(object):\n    def __init__(self):\n        self.label = \"Add Point Coordinates To Table\"\n        self.description = \"Modifies the attribute table of a point vector by adding fields containing each point's X and Y coordinates.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.add_point_coordinates_to_table(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AggregateRaster(object):\n    def __init__(self):\n        self.label = \"Aggregate Raster\"\n        self.description = \"Aggregates a raster to a lower resolution.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        agg_factor = arcpy.Parameter(\n            displayName=\"Aggregation Factor (pixels)\",\n            name=\"agg_factor\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        agg_factor.value = '2'\n\n        type = arcpy.Parameter(\n            displayName=\"Aggregation Type\",\n            name=\"type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        type.filter.type = \"ValueList\"\n        type.filter.list = ['mean', 'sum', 'maximum', 'minimum', 'range']\n        type.value = 'mean'\n\n        params = [i, output, agg_factor, type]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        agg_factor = parameters[2].valueAsText\n        type = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.aggregate_raster(i=i, output=output, agg_factor=agg_factor, type=type)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass And(object):\n    def __init__(self):\n        self.label = \"And\"\n        self.description = \"Performs a logical AND operator on two Boolean raster images.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.And(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Anova(object):\n    def __init__(self):\n        self.label = \"Anova\"\n        self.description = \"Performs an analysis of variance (ANOVA) test on a raster dataset.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        features = arcpy.Parameter(\n            displayName=\"Feature Definition (Class) File\",\n            name=\"features\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [i, features, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        features = parameters[1].valueAsText\n        if features is not None:\n            desc = arcpy.Describe(features)\n            features = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.anova(i=i, features=features, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ArcCos(object):\n    def __init__(self):\n        self.label = \"Arc Cos\"\n        self.description = \"Returns the inverse cosine (arccos) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.arc_cos(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ArcSin(object):\n    def __init__(self):\n        self.label = \"Arc Sin\"\n        self.description = \"Returns the inverse sine (arcsin) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.arc_sin(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ArcTan(object):\n    def __init__(self):\n        self.label = \"Arc Tan\"\n        self.description = \"Returns the inverse tangent (arctan) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.arc_tan(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Arcosh(object):\n    def __init__(self):\n        self.label = \"Arcosh\"\n        self.description = \"Returns the inverse hyperbolic cosine (arcosh) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.arcosh(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Arsinh(object):\n    def __init__(self):\n        self.label = \"Arsinh\"\n        self.description = \"Returns the inverse hyperbolic sine (arsinh) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.arsinh(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Artanh(object):\n    def __init__(self):\n        self.label = \"Artanh\"\n        self.description = \"Returns the inverse hyperbolic tangent (arctanh) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.artanh(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AsciiToLas(object):\n    def __init__(self):\n        self.label = \"Ascii To Las\"\n        self.description = \"Converts one or more ASCII files containing LiDAR points into LAS files.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input LiDAR point ASCII Files (.csv)\",\n            name=\"inputs\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n        inputs.filter.list = [\"csv\"]\n\n        pattern = arcpy.Parameter(\n            displayName=\"Pattern\",\n            name=\"pattern\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        proj = arcpy.Parameter(\n            displayName=\"Well-known-text (WKT) string or EPSG code\",\n            name=\"proj\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [inputs, pattern, proj]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        pattern = parameters[1].valueAsText\n        proj = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.ascii_to_las(inputs=inputs, pattern=pattern, proj=proj)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Aspect(object):\n    def __init__(self):\n        self.label = \"Aspect\"\n        self.description = \"Calculates an aspect raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        zfactor = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.aspect(dem=dem, output=output, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AssessRoute(object):\n    def __init__(self):\n        self.label = \"Assess Route\"\n        self.description = \"This tool assesses a route for slope, elevation, and visibility variation.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        routes = arcpy.Parameter(\n            displayName=\"Input Routes Vector\",\n            name=\"routes\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        routes.filter.list = [\"Polyline\"]\n\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Lines\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        length = arcpy.Parameter(\n            displayName=\"Max Segment Length\",\n            name=\"length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        dist = arcpy.Parameter(\n            displayName=\"Search Distance (grid cells)\",\n            name=\"dist\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        dist.value = '20'\n\n        params = [routes, dem, output, length, dist]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        routes = parameters[0].valueAsText\n        if routes is not None:\n            desc = arcpy.Describe(routes)\n            routes = desc.catalogPath\n        dem = parameters[1].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[2].valueAsText\n        length = parameters[3].valueAsText\n        dist = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.assess_route(routes=routes, dem=dem, output=output, length=length, dist=dist)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Atan2(object):\n    def __init__(self):\n        self.label = \"Atan2\"\n        self.description = \"Returns the 2-argument inverse tangent (atan2).\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input_y = arcpy.Parameter(\n            displayName=\"Input Y File Or Constant Value\",\n            name=\"input_y\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input_x = arcpy.Parameter(\n            displayName=\"Input X File Or Constant Value\",\n            name=\"input_x\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input_y, input_x, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input_y = parameters[0].valueAsText\n        if input_y is not None:\n            try:\n                input_y = str(float(input_y))\n            except:\n                desc = arcpy.Describe(input_y)\n                input_y = desc.catalogPath\n        input_x = parameters[1].valueAsText\n        if input_x is not None:\n            try:\n                input_x = str(float(input_x))\n            except:\n                desc = arcpy.Describe(input_x)\n                input_x = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.atan2(input_y=input_y, input_x=input_x, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AttributeCorrelation(object):\n    def __init__(self):\n        self.label = \"Attribute Correlation\"\n        self.description = \"Performs a correlation analysis on attribute fields from a vector database.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.attribute_correlation(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AttributeCorrelationNeighbourhoodAnalysis(object):\n    def __init__(self):\n        self.label = \"Attribute Correlation Neighbourhood Analysis\"\n        self.description = \"Performs a correlation on two input vector attributes within a neighbourhood search windows.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        field1 = arcpy.Parameter(\n            displayName=\"Field Name 1\",\n            name=\"field1\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field1.parameterDependencies = [i.name]\n\n        field2 = arcpy.Parameter(\n            displayName=\"Field Name 2\",\n            name=\"field2\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field2.parameterDependencies = [i.name]\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius (map units)\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        min_points = arcpy.Parameter(\n            displayName=\"Min. Number of Points\",\n            name=\"min_points\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        stat = arcpy.Parameter(\n            displayName=\"Correlation Statistic Type\",\n            name=\"stat\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        stat.filter.type = \"ValueList\"\n        stat.filter.list = ['pearson', 'kendall', 'spearman']\n        stat.value = 'pearson'\n\n        params = [i, field1, field2, radius, min_points, stat]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field1 = parameters[1].valueAsText\n        field2 = parameters[2].valueAsText\n        radius = parameters[3].valueAsText\n        min_points = parameters[4].valueAsText\n        stat = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.attribute_correlation_neighbourhood_analysis(i=i, field1=field1, field2=field2, radius=radius, min_points=min_points, stat=stat)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AttributeHistogram(object):\n    def __init__(self):\n        self.label = \"Attribute Histogram\"\n        self.description = \"Creates a histogram for the field values of a vector's attribute table.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [i, field, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.attribute_histogram(i=i, field=field, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AttributeScattergram(object):\n    def __init__(self):\n        self.label = \"Attribute Scattergram\"\n        self.description = \"Creates a scattergram for two field values of a vector's attribute table.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        fieldx = arcpy.Parameter(\n            displayName=\"Field Name X\",\n            name=\"fieldx\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        fieldx.parameterDependencies = [i.name]\n\n        fieldy = arcpy.Parameter(\n            displayName=\"Field Name Y\",\n            name=\"fieldy\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        fieldy.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        trendline = arcpy.Parameter(\n            displayName=\"Draw the trendline?\",\n            name=\"trendline\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        trendline.value = 'False'\n\n        params = [i, fieldx, fieldy, output, trendline]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        fieldx = parameters[1].valueAsText\n        fieldy = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        trendline = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.attribute_scattergram(i=i, fieldx=fieldx, fieldy=fieldy, output=output, trendline=trendline)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AverageFlowpathSlope(object):\n    def __init__(self):\n        self.label = \"Average Flowpath Slope\"\n        self.description = \"Measures the average slope gradient from each grid cell to all upslope divide cells.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.average_flowpath_slope(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AverageNormalVectorAngularDeviation(object):\n    def __init__(self):\n        self.label = \"Average Normal Vector Angular Deviation\"\n        self.description = \"Calculates the circular variance of aspect at a scale for a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Dimension\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '11'\n\n        params = [dem, output, filter]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.average_normal_vector_angular_deviation(dem=dem, output=output, filter=filter)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AverageOverlay(object):\n    def __init__(self):\n        self.label = \"Average Overlay\"\n        self.description = \"Calculates the average for each grid cell from a group of raster images.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.average_overlay(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass AverageUpslopeFlowpathLength(object):\n    def __init__(self):\n        self.label = \"Average Upslope Flowpath Length\"\n        self.description = \"Measures the average length of all upslope flowpaths draining each grid cell.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.average_upslope_flowpath_length(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BalanceContrastEnhancement(object):\n    def __init__(self):\n        self.label = \"Balance Contrast Enhancement\"\n        self.description = \"Performs a balance contrast enhancement on a colour-composite image of multispectral data.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Colour Composite Image File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        band_mean = arcpy.Parameter(\n            displayName=\"Band Mean Value\",\n            name=\"band_mean\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        band_mean.value = '100.0'\n\n        params = [i, output, band_mean]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        band_mean = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.balance_contrast_enhancement(i=i, output=output, band_mean=band_mean)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Basins(object):\n    def __init__(self):\n        self.label = \"Basins\"\n        self.description = \"Identifies drainage basins that drain to the DEM edge.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        output = parameters[1].valueAsText\n        esri_pntr = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.basins(d8_pntr=d8_pntr, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BilateralFilter(object):\n    def __init__(self):\n        self.label = \"Bilateral Filter\"\n        self.description = \"A bilateral filter is an edge-preserving smoothing filter introduced by Tomasi and Manduchi (1998).\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        sigma_dist = arcpy.Parameter(\n            displayName=\"Distance Standard Deviation (pixels)\",\n            name=\"sigma_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma_dist.value = '0.75'\n\n        sigma_int = arcpy.Parameter(\n            displayName=\"Intensity Standard Deviation (intensity units)\",\n            name=\"sigma_int\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma_int.value = '1.0'\n\n        params = [i, output, sigma_dist, sigma_int]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        sigma_dist = parameters[2].valueAsText\n        sigma_int = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.bilateral_filter(i=i, output=output, sigma_dist=sigma_dist, sigma_int=sigma_int)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BlockMaximumGridding(object):\n    def __init__(self):\n        self.label = \"Block Maximum Gridding\"\n        self.description = \"Creates a raster grid based on a set of vector points and assigns grid values using a block maximum scheme.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        use_z = arcpy.Parameter(\n            displayName=\"Use z-coordinate instead of field?\",\n            name=\"use_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_z.value = 'False'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, use_z, output, cell_size, base]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        use_z = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        cell_size = parameters[4].valueAsText\n        base = parameters[5].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.block_maximum_gridding(i=i, field=field, use_z=use_z, output=output, cell_size=cell_size, base=base)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BlockMinimumGridding(object):\n    def __init__(self):\n        self.label = \"Block Minimum Gridding\"\n        self.description = \"Creates a raster grid based on a set of vector points and assigns grid values using a block minimum scheme.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        use_z = arcpy.Parameter(\n            displayName=\"Use z-coordinate instead of field?\",\n            name=\"use_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_z.value = 'False'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, use_z, output, cell_size, base]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        use_z = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        cell_size = parameters[4].valueAsText\n        base = parameters[5].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.block_minimum_gridding(i=i, field=field, use_z=use_z, output=output, cell_size=cell_size, base=base)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BoundaryShapeComplexity(object):\n    def __init__(self):\n        self.label = \"Boundary Shape Complexity\"\n        self.description = \"Calculates the complexity of the boundaries of raster polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.boundary_shape_complexity(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BreachDepressions(object):\n    def __init__(self):\n        self.label = \"Breach Depressions\"\n        self.description = \"Breaches all of the depressions in a DEM using Lindsay's (2016) algorithm. This should be preferred over depression filling in most cases.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        max_depth = arcpy.Parameter(\n            displayName=\"Maximum Breach Depth (z units)\",\n            name=\"max_depth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_length = arcpy.Parameter(\n            displayName=\"Maximum Breach Channel Length (grid cells)\",\n            name=\"max_length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        flat_increment = arcpy.Parameter(\n            displayName=\"Flat increment value (z units)\",\n            name=\"flat_increment\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        fill_pits = arcpy.Parameter(\n            displayName=\"Fill single-cell pits?\",\n            name=\"fill_pits\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        fill_pits.value = 'False'\n\n        params = [dem, output, max_depth, max_length, flat_increment, fill_pits]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        max_depth = parameters[2].valueAsText\n        max_length = parameters[3].valueAsText\n        flat_increment = parameters[4].valueAsText\n        fill_pits = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.breach_depressions(dem=dem, output=output, max_depth=max_depth, max_length=max_length, flat_increment=flat_increment, fill_pits=fill_pits)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BreachDepressionsLeastCost(object):\n    def __init__(self):\n        self.label = \"Breach Depressions Least Cost\"\n        self.description = \"Breaches the depressions in a DEM using a least-cost pathway method.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        dist = arcpy.Parameter(\n            displayName=\"Maximum Search Distance (cells)\",\n            name=\"dist\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        max_cost = arcpy.Parameter(\n            displayName=\"Maximum Breach Cost (z units)\",\n            name=\"max_cost\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        min_dist = arcpy.Parameter(\n            displayName=\"Minimize breach distances?\",\n            name=\"min_dist\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_dist.value = 'True'\n\n        flat_increment = arcpy.Parameter(\n            displayName=\"Flat increment value (z units)\",\n            name=\"flat_increment\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        fill = arcpy.Parameter(\n            displayName=\"Fill unbreached depressions?\",\n            name=\"fill\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        fill.value = 'True'\n\n        params = [dem, output, dist, max_cost, min_dist, flat_increment, fill]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        dist = parameters[2].valueAsText\n        max_cost = parameters[3].valueAsText\n        min_dist = parameters[4].valueAsText\n        flat_increment = parameters[5].valueAsText\n        fill = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.breach_depressions_least_cost(dem=dem, output=output, dist=dist, max_cost=max_cost, min_dist=min_dist, flat_increment=flat_increment, fill=fill)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BreachSingleCellPits(object):\n    def __init__(self):\n        self.label = \"Breach Single Cell Pits\"\n        self.description = \"Removes single-cell pits from an input DEM by breaching.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.breach_single_cell_pits(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BreaklineMapping(object):\n    def __init__(self):\n        self.label = \"Breakline Mapping\"\n        self.description = \"This tool maps breaklines from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector Lines File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        threshold = arcpy.Parameter(\n            displayName=\"Threshold Value\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        threshold.value = '2.0'\n\n        min_length = arcpy.Parameter(\n            displayName=\"Min. Line Length (In Grid Cells)\",\n            name=\"min_length\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_length.value = '3'\n\n        params = [dem, output, threshold, min_length]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        threshold = parameters[2].valueAsText\n        min_length = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.breakline_mapping(dem=dem, output=output, threshold=threshold, min_length=min_length)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BufferRaster(object):\n    def __init__(self):\n        self.label = \"Buffer Raster\"\n        self.description = \"Maps a distance-based buffer around each non-background (non-zero/non-nodata) grid cell in an input image.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        size = arcpy.Parameter(\n            displayName=\"Buffer Size\",\n            name=\"size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        gridcells = arcpy.Parameter(\n            displayName=\"Buffer size measured in grid cells?\",\n            name=\"gridcells\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, size, gridcells]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        size = parameters[2].valueAsText\n        gridcells = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.buffer_raster(i=i, output=output, size=size, gridcells=gridcells)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass BurnStreamsAtRoads(object):\n    def __init__(self):\n        self.label = \"Burn Streams At Roads\"\n        self.description = \"Burns-in streams at the sites of road embankments.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Vector Streams File\",\n            name=\"streams\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        streams.filter.list = [\"Polyline\"]\n\n        roads = arcpy.Parameter(\n            displayName=\"Input Vector Roads File\",\n            name=\"roads\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        roads.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        width = arcpy.Parameter(\n            displayName=\"Road Embankment Width\",\n            name=\"width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, streams, roads, output, width]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        roads = parameters[2].valueAsText\n        if roads is not None:\n            desc = arcpy.Describe(roads)\n            roads = desc.catalogPath\n        output = parameters[3].valueAsText\n        width = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.burn_streams_at_roads(dem=dem, streams=streams, roads=roads, output=output, width=width)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CannyEdgeDetection(object):\n    def __init__(self):\n        self.label = \"Canny Edge Detection\"\n        self.description = \"This tool performs a Canny edge-detection filter on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster Image\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        sigma = arcpy.Parameter(\n            displayName=\"Sigma Value\",\n            name=\"sigma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma.value = '0.5'\n\n        low = arcpy.Parameter(\n            displayName=\"Low Threshold\",\n            name=\"low\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        low.value = '0.05'\n\n        high = arcpy.Parameter(\n            displayName=\"High Threshold\",\n            name=\"high\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        high.value = '0.15'\n\n        add_back = arcpy.Parameter(\n            displayName=\"Add edge back to the image?\",\n            name=\"add_back\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        add_back.value = 'False'\n\n        params = [i, output, sigma, low, high, add_back]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        sigma = parameters[2].valueAsText\n        low = parameters[3].valueAsText\n        high = parameters[4].valueAsText\n        add_back = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.canny_edge_detection(i=i, output=output, sigma=sigma, low=low, high=high, add_back=add_back)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Ceil(object):\n    def __init__(self):\n        self.label = \"Ceil\"\n        self.description = \"Returns the smallest (closest to negative infinity) value that is greater than or equal to the values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.ceil(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Centroid(object):\n    def __init__(self):\n        self.label = \"Centroid\"\n        self.description = \"Calculates the centroid, or average location, of raster polygon objects.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        text_output = arcpy.Parameter(\n            displayName=\"Output text?\",\n            name=\"text_output\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, output, text_output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        text_output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.centroid(i=i, output=output, text_output=text_output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CentroidVector(object):\n    def __init__(self):\n        self.label = \"Centroid Vector\"\n        self.description = \"Identifies the centroid point of a vector polyline or polygon feature or a group of vector points.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.centroid_vector(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ChangeVectorAnalysis(object):\n    def __init__(self):\n        self.label = \"Change Vector Analysis\"\n        self.description = \"Performs a change vector analysis on a two-date multi-spectral dataset.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        date1 = arcpy.Parameter(\n            displayName=\"Earlier Date Input Files\",\n            name=\"date1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        date1.multiValue = True\n\n        date2 = arcpy.Parameter(\n            displayName=\"Later Date Input Files\",\n            name=\"date2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        date2.multiValue = True\n\n        magnitude = arcpy.Parameter(\n            displayName=\"Output Vector Magnitude File\",\n            name=\"magnitude\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        magnitude.filter.list = [\"tif\"]\n\n        direction = arcpy.Parameter(\n            displayName=\"Output Vector Direction File\",\n            name=\"direction\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        direction.filter.list = [\"tif\"]\n\n        params = [date1, date2, magnitude, direction]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        date1 = parameters[0].valueAsText\n        if date1 is not None:\n            items = date1.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            date1 = \";\".join(items_path)\n        date2 = parameters[1].valueAsText\n        if date2 is not None:\n            items = date2.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            date2 = \";\".join(items_path)\n        magnitude = parameters[2].valueAsText\n        direction = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.change_vector_analysis(date1=date1, date2=date2, magnitude=magnitude, direction=direction)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CircularVarianceOfAspect(object):\n    def __init__(self):\n        self.label = \"Circular Variance Of Aspect\"\n        self.description = \"Calculates the circular variance of aspect at a scale for a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Dimension\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '11'\n\n        params = [dem, output, filter]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.circular_variance_of_aspect(dem=dem, output=output, filter=filter)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ClassifyBuildingsInLidar(object):\n    def __init__(self):\n        self.label = \"Classify Buildings In Lidar\"\n        self.description = \"Reclassifies a LiDAR points that lie within vector building footprints.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        buildings = arcpy.Parameter(\n            displayName=\"Input Building Polygon File\",\n            name=\"buildings\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        buildings.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, buildings, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        buildings = parameters[1].valueAsText\n        if buildings is not None:\n            desc = arcpy.Describe(buildings)\n            buildings = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.classify_buildings_in_lidar(i=i, buildings=buildings, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ClassifyLidar(object):\n    def __init__(self):\n        self.label = \"Classify Lidar\"\n        self.description = \"Classify points within a LiDAR point cloud based on point properties.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR Points\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Distance:\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '1.5'\n\n        grd_threshold = arcpy.Parameter(\n            displayName=\"Ground Threshold:\",\n            name=\"grd_threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        grd_threshold.value = '0.1'\n\n        oto_threshold = arcpy.Parameter(\n            displayName=\"Off-Terrain Object Threshold:\",\n            name=\"oto_threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        oto_threshold.value = '2.0'\n\n        planarity_threshold = arcpy.Parameter(\n            displayName=\"Planarity Threshold:\",\n            name=\"planarity_threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        planarity_threshold.value = '0.85'\n\n        linearity_threshold = arcpy.Parameter(\n            displayName=\"Linearity Threshold:\",\n            name=\"linearity_threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        linearity_threshold.value = '0.70'\n\n        iterations = arcpy.Parameter(\n            displayName=\"Number of Iterations:\",\n            name=\"iterations\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        iterations.value = '30'\n\n        facade_threshold = arcpy.Parameter(\n            displayName=\"Facade Threshold:\",\n            name=\"facade_threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        facade_threshold.value = '0.5'\n\n        params = [i, output, radius, grd_threshold, oto_threshold, planarity_threshold, linearity_threshold, iterations, facade_threshold]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        radius = parameters[2].valueAsText\n        grd_threshold = parameters[3].valueAsText\n        oto_threshold = parameters[4].valueAsText\n        planarity_threshold = parameters[5].valueAsText\n        linearity_threshold = parameters[6].valueAsText\n        iterations = parameters[7].valueAsText\n        facade_threshold = parameters[8].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.classify_lidar(i=i, output=output, radius=radius, grd_threshold=grd_threshold, oto_threshold=oto_threshold, planarity_threshold=planarity_threshold, linearity_threshold=linearity_threshold, iterations=iterations, facade_threshold=facade_threshold)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ClassifyOverlapPoints(object):\n    def __init__(self):\n        self.label = \"Classify Overlap Points\"\n        self.description = \"Classifies or filters LAS points in regions of overlapping flight lines.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        resolution = arcpy.Parameter(\n            displayName=\"Sample Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '2.0'\n\n        criterion = arcpy.Parameter(\n            displayName=\"Overlap Criterion\",\n            name=\"criterion\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        criterion.filter.type = \"ValueList\"\n        criterion.filter.list = ['max scan angle', 'not min point source ID', 'not min time', 'multiple point source IDs']\n        criterion.value = 'max scan angle'\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter out points from overlapping flightlines?\",\n            name=\"filter\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = 'False'\n\n        params = [i, output, resolution, criterion, filter]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        resolution = parameters[2].valueAsText\n        criterion = parameters[3].valueAsText\n        filter = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.classify_overlap_points(i=i, output=output, resolution=resolution, criterion=criterion, filter=filter)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CleanVector(object):\n    def __init__(self):\n        self.label = \"Clean Vector\"\n        self.description = \"Removes null features and lines/polygons with fewer than the required number of vertices.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.clean_vector(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Clip(object):\n    def __init__(self):\n        self.label = \"Clip\"\n        self.description = \"Extract all the features, or parts of features, that overlap with the features of the clip vector.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        clip = arcpy.Parameter(\n            displayName=\"Input Clip Polygon Vector File\",\n            name=\"clip\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        clip.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, clip, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        clip = parameters[1].valueAsText\n        if clip is not None:\n            desc = arcpy.Describe(clip)\n            clip = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.clip(i=i, clip=clip, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ClipLidarToPolygon(object):\n    def __init__(self):\n        self.label = \"Clip Lidar To Polygon\"\n        self.description = \"Clips a LiDAR point cloud to a vector polygon or polygons.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        polygons = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"polygons\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        polygons.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, polygons, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        polygons = parameters[1].valueAsText\n        if polygons is not None:\n            desc = arcpy.Describe(polygons)\n            polygons = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.clip_lidar_to_polygon(i=i, polygons=polygons, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ClipRasterToPolygon(object):\n    def __init__(self):\n        self.label = \"Clip Raster To Polygon\"\n        self.description = \"Clips a raster to a vector polygon.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        polygons = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"polygons\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        polygons.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        maintain_dimensions = arcpy.Parameter(\n            displayName=\"Maintain input raster dimensions?\",\n            name=\"maintain_dimensions\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        maintain_dimensions.value = 'False'\n\n        params = [i, polygons, output, maintain_dimensions]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        polygons = parameters[1].valueAsText\n        if polygons is not None:\n            desc = arcpy.Describe(polygons)\n            polygons = desc.catalogPath\n        output = parameters[2].valueAsText\n        maintain_dimensions = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.clip_raster_to_polygon(i=i, polygons=polygons, output=output, maintain_dimensions=maintain_dimensions)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Closing(object):\n    def __init__(self):\n        self.label = \"Closing\"\n        self.description = \"A closing is a mathematical morphology operation involving an erosion (min filter) of a dilation (max filter) set.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.closing(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Clump(object):\n    def __init__(self):\n        self.label = \"Clump\"\n        self.description = \"Groups cells that form discrete areas, assigning them unique identifiers.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        diag = arcpy.Parameter(\n            displayName=\"Include diagonal connections?\",\n            name=\"diag\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        diag.value = 'True'\n\n        zero_back = arcpy.Parameter(\n            displayName=\"Treat zero values as background?\",\n            name=\"zero_back\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, output, diag, zero_back]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        diag = parameters[2].valueAsText\n        zero_back = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.clump(i=i, output=output, diag=diag, zero_back=zero_back)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ColourizeBasedOnClass(object):\n    def __init__(self):\n        self.label = \"Colourize Based On Class\"\n        self.description = \"Sets the RGB values of a LiDAR point cloud based on the point classification values.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR Points\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        intensity_blending = arcpy.Parameter(\n            displayName=\"Intensity Blending Amount (0-100%):\",\n            name=\"intensity_blending\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        intensity_blending.value = '50.0'\n\n        clr_str = arcpy.Parameter(\n            displayName=\"Colour values:\",\n            name=\"clr_str\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_unique_clrs_for_buildings = arcpy.Parameter(\n            displayName=\"Use unique colours for each building?\",\n            name=\"use_unique_clrs_for_buildings\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_unique_clrs_for_buildings.value = 'False'\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Distance:\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        params = [i, output, intensity_blending, clr_str, use_unique_clrs_for_buildings, radius]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        intensity_blending = parameters[2].valueAsText\n        clr_str = parameters[3].valueAsText\n        use_unique_clrs_for_buildings = parameters[4].valueAsText\n        radius = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.colourize_based_on_class(i=i, output=output, intensity_blending=intensity_blending, clr_str=clr_str, use_unique_clrs_for_buildings=use_unique_clrs_for_buildings, radius=radius)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ColourizeBasedOnPointReturns(object):\n    def __init__(self):\n        self.label = \"Colourize Based On Point Returns\"\n        self.description = \"Sets the RGB values of a LiDAR point cloud based on the point returns.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR Points\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        intensity_blending = arcpy.Parameter(\n            displayName=\"Intensity Blending Amount (0-100%):\",\n            name=\"intensity_blending\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        intensity_blending.value = '50.0'\n\n        only = arcpy.Parameter(\n            displayName=\"Only Return Colour\",\n            name=\"only\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        only.value = '(230,214,170)'\n\n        first = arcpy.Parameter(\n            displayName=\"First Return Colour\",\n            name=\"first\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        first.value = '(0,140,0)'\n\n        intermediate = arcpy.Parameter(\n            displayName=\"Intermediate Return Colour\",\n            name=\"intermediate\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        intermediate.value = '(255,0,255)'\n\n        last = arcpy.Parameter(\n            displayName=\"Last Return Colour\",\n            name=\"last\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        last.value = '(0,0,255)'\n\n        params = [i, output, intensity_blending, only, first, intermediate, last]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        intensity_blending = parameters[2].valueAsText\n        only = parameters[3].valueAsText\n        first = parameters[4].valueAsText\n        intermediate = parameters[5].valueAsText\n        last = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.colourize_based_on_point_returns(i=i, output=output, intensity_blending=intensity_blending, only=only, first=first, intermediate=intermediate, last=last)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CompactnessRatio(object):\n    def __init__(self):\n        self.label = \"Compactness Ratio\"\n        self.description = \"Calculates the compactness ratio (A/P), a measure of shape complexity, for vector polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.compactness_ratio(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ConditionalEvaluation(object):\n    def __init__(self):\n        self.label = \"Conditional Evaluation\"\n        self.description = \"Performs a conditional evaluation (if-then-else) operation on a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        statement = arcpy.Parameter(\n            displayName=\"Conditional Statement e.g. value > 35.0:\",\n            name=\"statement\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        true = arcpy.Parameter(\n            displayName=\"Value Where TRUE (Raster File Or Constant Value)\",\n            name=\"true\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        false = arcpy.Parameter(\n            displayName=\"Value Where FALSE (Raster File Or Constant Value)\",\n            name=\"false\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, statement, true, false, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        statement = parameters[1].valueAsText\n        true = parameters[2].valueAsText\n        if true is not None:\n            try:\n                true = str(float(true))\n            except:\n                desc = arcpy.Describe(true)\n                true = desc.catalogPath\n        false = parameters[3].valueAsText\n        if false is not None:\n            try:\n                false = str(float(false))\n            except:\n                desc = arcpy.Describe(false)\n                false = desc.catalogPath\n        output = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.conditional_evaluation(i=i, statement=statement, true=true, false=false, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ConditionedLatinHypercube(object):\n    def __init__(self):\n        self.label = \"Conditioned Latin Hypercube\"\n        self.description = \"Implements conditioned Latin Hypercube sampling.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Raster\",\n            name=\"inputs\",\n            datatype=[\"DERasterDataset\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output shapefile\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        samples = arcpy.Parameter(\n            displayName=\"Number of sample sites\",\n            name=\"samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        samples.value = '500'\n\n        iterations = arcpy.Parameter(\n            displayName=\"Number of resampling iterations\",\n            name=\"iterations\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        iterations.value = '25000'\n\n        seed = arcpy.Parameter(\n            displayName=\"RNG seed\",\n            name=\"seed\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        prob = arcpy.Parameter(\n            displayName=\"Random resample probability\",\n            name=\"prob\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        prob.value = '0.5'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Objective function threshold.\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        temp = arcpy.Parameter(\n            displayName=\"Initial annealing temperature\",\n            name=\"temp\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        temp.value = '1.0'\n\n        temp_decay = arcpy.Parameter(\n            displayName=\"Temperature decay factor\",\n            name=\"temp_decay\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        temp_decay.value = '0.05'\n\n        cycle = arcpy.Parameter(\n            displayName=\"Annealing cycle duration\",\n            name=\"cycle\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        cycle.value = '10'\n\n        average = arcpy.Parameter(\n            displayName=\"Average the continuous Obj. Func.\",\n            name=\"average\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        average.value = 'False'\n\n        params = [inputs, output, samples, iterations, seed, prob, threshold, temp, temp_decay, cycle, average]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        samples = parameters[2].valueAsText\n        iterations = parameters[3].valueAsText\n        seed = parameters[4].valueAsText\n        prob = parameters[5].valueAsText\n        threshold = parameters[6].valueAsText\n        temp = parameters[7].valueAsText\n        temp_decay = parameters[8].valueAsText\n        cycle = parameters[9].valueAsText\n        average = parameters[10].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.conditioned_latin_hypercube(inputs=inputs, output=output, samples=samples, iterations=iterations, seed=seed, prob=prob, threshold=threshold, temp=temp, temp_decay=temp_decay, cycle=cycle, average=average)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ConservativeSmoothingFilter(object):\n    def __init__(self):\n        self.label = \"Conservative Smoothing Filter\"\n        self.description = \"Performs a conservative-smoothing filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '3'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '3'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.conservative_smoothing_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ConstructVectorTin(object):\n    def __init__(self):\n        self.label = \"Construct Vector Tin\"\n        self.description = \"Creates a vector triangular irregular network (TIN) for a set of vector points.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        use_z = arcpy.Parameter(\n            displayName=\"Use Shapefile 'z' values?\",\n            name=\"use_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_z.value = 'False'\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        max_triangle_edge_length = arcpy.Parameter(\n            displayName=\"Maximum Triangle Edge Length (optional)\",\n            name=\"max_triangle_edge_length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, use_z, output, max_triangle_edge_length]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        use_z = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        max_triangle_edge_length = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.construct_vector_tin(i=i, field=field, use_z=use_z, output=output, max_triangle_edge_length=max_triangle_edge_length)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ContoursFromPoints(object):\n    def __init__(self):\n        self.label = \"Contours From Points\"\n        self.description = \"Creates a contour coverage from a set of input points.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        use_z = arcpy.Parameter(\n            displayName=\"Use Shapefile 'z' values?\",\n            name=\"use_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_z.value = 'False'\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector Lines File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        max_triangle_edge_length = arcpy.Parameter(\n            displayName=\"Maximum Triangle Edge Length (optional)\",\n            name=\"max_triangle_edge_length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        interval = arcpy.Parameter(\n            displayName=\"Contour Interval\",\n            name=\"interval\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        interval.value = '10.0'\n\n        base = arcpy.Parameter(\n            displayName=\"Base Contour\",\n            name=\"base\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        base.value = '0.0'\n\n        smooth = arcpy.Parameter(\n            displayName=\"Smoothing Filter Size\",\n            name=\"smooth\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        smooth.value = '5'\n\n        params = [i, field, use_z, output, max_triangle_edge_length, interval, base, smooth]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        use_z = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        max_triangle_edge_length = parameters[4].valueAsText\n        interval = parameters[5].valueAsText\n        base = parameters[6].valueAsText\n        smooth = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.contours_from_points(i=i, field=field, use_z=use_z, output=output, max_triangle_edge_length=max_triangle_edge_length, interval=interval, base=base, smooth=smooth)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ContoursFromRaster(object):\n    def __init__(self):\n        self.label = \"Contours From Raster\"\n        self.description = \"Derives a vector contour coverage from a raster surface.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster Surface File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Contour File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        interval = arcpy.Parameter(\n            displayName=\"Contour Interval\",\n            name=\"interval\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        interval.value = '10.0'\n\n        base = arcpy.Parameter(\n            displayName=\"Base Contour\",\n            name=\"base\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        base.value = '0.0'\n\n        smooth = arcpy.Parameter(\n            displayName=\"Smoothing Filter Size\",\n            name=\"smooth\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        smooth.value = '9'\n\n        tolerance = arcpy.Parameter(\n            displayName=\"Tolerance\",\n            name=\"tolerance\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        tolerance.value = '10.0'\n\n        params = [i, output, interval, base, smooth, tolerance]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        interval = parameters[2].valueAsText\n        base = parameters[3].valueAsText\n        smooth = parameters[4].valueAsText\n        tolerance = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.contours_from_raster(i=i, output=output, interval=interval, base=base, smooth=smooth, tolerance=tolerance)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ConvertNodataToZero(object):\n    def __init__(self):\n        self.label = \"Convert Nodata To Zero\"\n        self.description = \"Converts nodata values in a raster to zero.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.convert_nodata_to_zero(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ConvertRasterFormat(object):\n    def __init__(self):\n        self.label = \"Convert Raster Format\"\n        self.description = \"Converts raster data from one format to another.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.convert_raster_format(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CornerDetection(object):\n    def __init__(self):\n        self.label = \"Corner Detection\"\n        self.description = \"Identifies corner patterns in boolean images using hit-and-miss pattern matching.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.corner_detection(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CorrectVignetting(object):\n    def __init__(self):\n        self.label = \"Correct Vignetting\"\n        self.description = \"Corrects the darkening of images towards corners.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        pp = arcpy.Parameter(\n            displayName=\"Input Principal Point File\",\n            name=\"pp\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        pp.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        focal_length = arcpy.Parameter(\n            displayName=\"Camera Focal Length (mm)\",\n            name=\"focal_length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        focal_length.value = '304.8'\n\n        image_width = arcpy.Parameter(\n            displayName=\"Distance Between Left-Right Edges (mm)\",\n            name=\"image_width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        image_width.value = '228.6'\n\n        n = arcpy.Parameter(\n            displayName=\"n Parameter\",\n            name=\"n\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        n.value = '4.0'\n\n        params = [i, pp, output, focal_length, image_width, n]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        pp = parameters[1].valueAsText\n        if pp is not None:\n            desc = arcpy.Describe(pp)\n            pp = desc.catalogPath\n        output = parameters[2].valueAsText\n        focal_length = parameters[3].valueAsText\n        image_width = parameters[4].valueAsText\n        n = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.correct_vignetting(i=i, pp=pp, output=output, focal_length=focal_length, image_width=image_width, n=n)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Cos(object):\n    def __init__(self):\n        self.label = \"Cos\"\n        self.description = \"Returns the cosine (cos) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.cos(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Cosh(object):\n    def __init__(self):\n        self.label = \"Cosh\"\n        self.description = \"Returns the hyperbolic cosine (cosh) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.cosh(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CostAllocation(object):\n    def __init__(self):\n        self.label = \"Cost Allocation\"\n        self.description = \"Identifies the source cell to which each grid cell is connected by a least-cost pathway in a cost-distance analysis.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        source = arcpy.Parameter(\n            displayName=\"Input Source File\",\n            name=\"source\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        backlink = arcpy.Parameter(\n            displayName=\"Input Backlink File\",\n            name=\"backlink\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [source, backlink, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        source = parameters[0].valueAsText\n        if source is not None:\n            desc = arcpy.Describe(source)\n            source = desc.catalogPath\n        backlink = parameters[1].valueAsText\n        if backlink is not None:\n            desc = arcpy.Describe(backlink)\n            backlink = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.cost_allocation(source=source, backlink=backlink, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CostDistance(object):\n    def __init__(self):\n        self.label = \"Cost Distance\"\n        self.description = \"Performs cost-distance accumulation on a cost surface and a group of source cells.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        source = arcpy.Parameter(\n            displayName=\"Input Source File\",\n            name=\"source\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        cost = arcpy.Parameter(\n            displayName=\"Input Cost (Friction) File\",\n            name=\"cost\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_accum = arcpy.Parameter(\n            displayName=\"Output Cost Accumulation File\",\n            name=\"out_accum\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_accum.filter.list = [\"tif\"]\n\n        out_backlink = arcpy.Parameter(\n            displayName=\"Output Backlink File\",\n            name=\"out_backlink\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_backlink.filter.list = [\"tif\"]\n\n        params = [source, cost, out_accum, out_backlink]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        source = parameters[0].valueAsText\n        if source is not None:\n            desc = arcpy.Describe(source)\n            source = desc.catalogPath\n        cost = parameters[1].valueAsText\n        if cost is not None:\n            desc = arcpy.Describe(cost)\n            cost = desc.catalogPath\n        out_accum = parameters[2].valueAsText\n        out_backlink = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.cost_distance(source=source, cost=cost, out_accum=out_accum, out_backlink=out_backlink)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CostPathway(object):\n    def __init__(self):\n        self.label = \"Cost Pathway\"\n        self.description = \"Performs cost-distance pathway analysis using a series of destination grid cells.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        destination = arcpy.Parameter(\n            displayName=\"Input Destination File\",\n            name=\"destination\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        backlink = arcpy.Parameter(\n            displayName=\"Input Backlink File\",\n            name=\"backlink\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Treat zero values as background?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [destination, backlink, output, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        destination = parameters[0].valueAsText\n        if destination is not None:\n            desc = arcpy.Describe(destination)\n            destination = desc.catalogPath\n        backlink = parameters[1].valueAsText\n        if backlink is not None:\n            desc = arcpy.Describe(backlink)\n            backlink = desc.catalogPath\n        output = parameters[2].valueAsText\n        zero_background = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.cost_pathway(destination=destination, backlink=backlink, output=output, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CountIf(object):\n    def __init__(self):\n        self.label = \"Count If\"\n        self.description = \"Counts the number of occurrences of a specified value in a cell-stack of rasters.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        value = arcpy.Parameter(\n            displayName=\"Value\",\n            name=\"value\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [inputs, output, value]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        value = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.count_if(inputs=inputs, output=output, value=value)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CreateColourComposite(object):\n    def __init__(self):\n        self.label = \"Create Colour Composite\"\n        self.description = \"Creates a colour-composite image from three bands of multispectral imagery.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        red = arcpy.Parameter(\n            displayName=\"Input Red Band Image File\",\n            name=\"red\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        green = arcpy.Parameter(\n            displayName=\"Input Green Band Image File\",\n            name=\"green\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        blue = arcpy.Parameter(\n            displayName=\"Input Blue Band Image File\",\n            name=\"blue\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        opacity = arcpy.Parameter(\n            displayName=\"Input Opacity Band Image File (Optional)\",\n            name=\"opacity\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Colour Composite File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        enhance = arcpy.Parameter(\n            displayName=\"Perform balance contrast enhancement?\",\n            name=\"enhance\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        enhance.value = 'True'\n\n        zeros = arcpy.Parameter(\n            displayName=\"Treat zeros as nodata?\",\n            name=\"zeros\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zeros.value = 'False'\n\n        params = [red, green, blue, opacity, output, enhance, zeros]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        red = parameters[0].valueAsText\n        if red is not None:\n            desc = arcpy.Describe(red)\n            red = desc.catalogPath\n        green = parameters[1].valueAsText\n        if green is not None:\n            desc = arcpy.Describe(green)\n            green = desc.catalogPath\n        blue = parameters[2].valueAsText\n        if blue is not None:\n            desc = arcpy.Describe(blue)\n            blue = desc.catalogPath\n        opacity = parameters[3].valueAsText\n        if opacity is not None:\n            desc = arcpy.Describe(opacity)\n            opacity = desc.catalogPath\n        output = parameters[4].valueAsText\n        enhance = parameters[5].valueAsText\n        zeros = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.create_colour_composite(red=red, green=green, blue=blue, opacity=opacity, output=output, enhance=enhance, zeros=zeros)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CreateHexagonalVectorGrid(object):\n    def __init__(self):\n        self.label = \"Create Hexagonal Vector Grid\"\n        self.description = \"Creates a hexagonal vector grid.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        input = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"input\",\n            datatype=[\"DERasterDataset\", \"DEShapefile\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        width = arcpy.Parameter(\n            displayName=\"Hexagon Width\",\n            name=\"width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        orientation = arcpy.Parameter(\n            displayName=\"Grid Orientation\",\n            name=\"orientation\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        orientation.filter.type = \"ValueList\"\n        orientation.filter.list = ['horizontal', 'vertical']\n        orientation.value = 'horizontal'\n\n        params = [input, output, width, orientation]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        width = parameters[2].valueAsText\n        orientation = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.create_hexagonal_vector_grid(i=i, output=output, width=width, orientation=orientation)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CreatePlane(object):\n    def __init__(self):\n        self.label = \"Create Plane\"\n        self.description = \"Creates a raster image based on the equation for a simple plane.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        base = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        gradient = arcpy.Parameter(\n            displayName=\"Gradient\",\n            name=\"gradient\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        gradient.value = '15.0'\n\n        aspect = arcpy.Parameter(\n            displayName=\"Aspect\",\n            name=\"aspect\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        aspect.value = '90.0'\n\n        constant = arcpy.Parameter(\n            displayName=\"Constant\",\n            name=\"constant\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        constant.value = '0.0'\n\n        params = [base, output, gradient, aspect, constant]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        base = parameters[0].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        output = parameters[1].valueAsText\n        gradient = parameters[2].valueAsText\n        aspect = parameters[3].valueAsText\n        constant = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.create_plane(base=base, output=output, gradient=gradient, aspect=aspect, constant=constant)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CreateRectangularVectorGrid(object):\n    def __init__(self):\n        self.label = \"Create Rectangular Vector Grid\"\n        self.description = \"Creates a rectangular vector grid.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        input = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"input\",\n            datatype=[\"DERasterDataset\", \"DEShapefile\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        width = arcpy.Parameter(\n            displayName=\"Grid Cell Width\",\n            name=\"width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        height = arcpy.Parameter(\n            displayName=\"Grid Cell Height\",\n            name=\"height\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        xorig = arcpy.Parameter(\n            displayName=\"Grid origin x-coordinate\",\n            name=\"xorig\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        xorig.value = '0'\n\n        yorig = arcpy.Parameter(\n            displayName=\"Grid origin y-coordinate\",\n            name=\"yorig\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        yorig.value = '0'\n\n        params = [input, output, width, height, xorig, yorig]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        width = parameters[2].valueAsText\n        height = parameters[3].valueAsText\n        xorig = parameters[4].valueAsText\n        yorig = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.create_rectangular_vector_grid(i=i, output=output, width=width, height=height, xorig=xorig, yorig=yorig)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CrispnessIndex(object):\n    def __init__(self):\n        self.label = \"Crispness Index\"\n        self.description = \"Calculates the Crispness Index, which is used to quantify how crisp (or conversely how fuzzy) a probability image is.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.crispness_index(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CrossTabulation(object):\n    def __init__(self):\n        self.label = \"Cross Tabulation\"\n        self.description = \"Performs a cross-tabulation on two categorical images.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File 1\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File 2\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.cross_tabulation(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CsvPointsToVector(object):\n    def __init__(self):\n        self.label = \"Csv Points To Vector\"\n        self.description = \"Converts a CSV text file to vector points.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input CSV File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"csv\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        xfield = arcpy.Parameter(\n            displayName=\"X Field Number (zero-based)\",\n            name=\"xfield\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        xfield.value = '0'\n\n        yfield = arcpy.Parameter(\n            displayName=\"Y Field Number (zero-based)\",\n            name=\"yfield\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        yfield.value = '1'\n\n        epsg = arcpy.Parameter(\n            displayName=\"EPSG Projection\",\n            name=\"epsg\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, xfield, yfield, epsg]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        xfield = parameters[2].valueAsText\n        yfield = parameters[3].valueAsText\n        epsg = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.csv_points_to_vector(i=i, output=output, xfield=xfield, yfield=yfield, epsg=epsg)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass CumulativeDistribution(object):\n    def __init__(self):\n        self.label = \"Cumulative Distribution\"\n        self.description = \"Converts a raster image to its cumulative distribution function.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.cumulative_distribution(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Curvedness(object):\n    def __init__(self):\n        self.label = \"Curvedness\"\n        self.description = \"This tool calculates curvedness from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.curvedness(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass D8FlowAccumulation(object):\n    def __init__(self):\n        self.label = \"D8 Flow Accumulation\"\n        self.description = \"Calculates a D8 flow accumulation raster from an input DEM or flow pointer.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input DEM or D8 Pointer File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['cells', 'catchment area', 'specific contributing area']\n        out_type.value = 'cells'\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip the upper tail by 1%?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        pntr = arcpy.Parameter(\n            displayName=\"Is the input raster a D8 flow pointer?\",\n            name=\"pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"If a pointer is input, does it use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [i, output, out_type, log, clip, pntr, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_type = parameters[2].valueAsText\n        log = parameters[3].valueAsText\n        clip = parameters[4].valueAsText\n        pntr = parameters[5].valueAsText\n        esri_pntr = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.d8_flow_accumulation(i=i, output=output, out_type=out_type, log=log, clip=clip, pntr=pntr, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass D8MassFlux(object):\n    def __init__(self):\n        self.label = \"D8 Mass Flux\"\n        self.description = \"Performs a D8 mass flux calculation.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        loading = arcpy.Parameter(\n            displayName=\"Input Loading File\",\n            name=\"loading\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        efficiency = arcpy.Parameter(\n            displayName=\"Input Efficiency File\",\n            name=\"efficiency\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        absorption = arcpy.Parameter(\n            displayName=\"Input Absorption File\",\n            name=\"absorption\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, loading, efficiency, absorption, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        loading = parameters[1].valueAsText\n        if loading is not None:\n            desc = arcpy.Describe(loading)\n            loading = desc.catalogPath\n        efficiency = parameters[2].valueAsText\n        if efficiency is not None:\n            desc = arcpy.Describe(efficiency)\n            efficiency = desc.catalogPath\n        absorption = parameters[3].valueAsText\n        if absorption is not None:\n            desc = arcpy.Describe(absorption)\n            absorption = desc.catalogPath\n        output = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.d8_mass_flux(dem=dem, loading=loading, efficiency=efficiency, absorption=absorption, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass D8Pointer(object):\n    def __init__(self):\n        self.label = \"D8 Pointer\"\n        self.description = \"Calculates a D8 flow pointer raster from an input DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Should the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [dem, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        esri_pntr = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.d8_pointer(dem=dem, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DInfFlowAccumulation(object):\n    def __init__(self):\n        self.label = \"D Inf Flow Accumulation\"\n        self.description = \"Calculates a D-infinity flow accumulation raster from an input DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input DEM or D-inf Pointer File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['Cells', 'Specific Contributing Area', 'Catchment Area']\n        out_type.value = 'Specific Contributing Area'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Convergence Threshold (grid cells; blank for none)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip the upper tail by 1%?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        pntr = arcpy.Parameter(\n            displayName=\"Is the input raster a D-inf flow pointer?\",\n            name=\"pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, out_type, threshold, log, clip, pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_type = parameters[2].valueAsText\n        threshold = parameters[3].valueAsText\n        log = parameters[4].valueAsText\n        clip = parameters[5].valueAsText\n        pntr = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.d_inf_flow_accumulation(i=i, output=output, out_type=out_type, threshold=threshold, log=log, clip=clip, pntr=pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DInfMassFlux(object):\n    def __init__(self):\n        self.label = \"D Inf Mass Flux\"\n        self.description = \"Performs a D-infinity mass flux calculation.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        loading = arcpy.Parameter(\n            displayName=\"Input Loading File\",\n            name=\"loading\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        efficiency = arcpy.Parameter(\n            displayName=\"Input Efficiency File\",\n            name=\"efficiency\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        absorption = arcpy.Parameter(\n            displayName=\"Input Absorption File\",\n            name=\"absorption\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, loading, efficiency, absorption, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        loading = parameters[1].valueAsText\n        if loading is not None:\n            desc = arcpy.Describe(loading)\n            loading = desc.catalogPath\n        efficiency = parameters[2].valueAsText\n        if efficiency is not None:\n            desc = arcpy.Describe(efficiency)\n            efficiency = desc.catalogPath\n        absorption = parameters[3].valueAsText\n        if absorption is not None:\n            desc = arcpy.Describe(absorption)\n            absorption = desc.catalogPath\n        output = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.d_inf_mass_flux(dem=dem, loading=loading, efficiency=efficiency, absorption=absorption, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DInfPointer(object):\n    def __init__(self):\n        self.label = \"D Inf Pointer\"\n        self.description = \"Calculates a D-infinity flow pointer (flow direction) raster from an input DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.d_inf_pointer(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Dbscan(object):\n    def __init__(self):\n        self.label = \"Dbscan\"\n        self.description = \"Performs a DBSCAN-based unsupervised clustering operation.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Rasters\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        scaling = arcpy.Parameter(\n            displayName=\"Scaling Method\",\n            name=\"scaling\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        scaling.filter.type = \"ValueList\"\n        scaling.filter.list = ['None', 'Normalize', 'Standardize']\n        scaling.value = 'Normalize'\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        search_dist = arcpy.Parameter(\n            displayName=\"Search distance\",\n            name=\"search_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        search_dist.value = '0.01'\n\n        min_points = arcpy.Parameter(\n            displayName=\"Minimum Points\",\n            name=\"min_points\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_points.value = '5'\n\n        params = [inputs, scaling, output, search_dist, min_points]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        scaling = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        search_dist = parameters[3].valueAsText\n        min_points = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.dbscan(inputs=inputs, scaling=scaling, output=output, search_dist=search_dist, min_points=min_points)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Decrement(object):\n    def __init__(self):\n        self.label = \"Decrement\"\n        self.description = \"Decreases the values of each grid cell in an input raster by 1.0 (see also InPlaceSubtract).\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.decrement(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DemVoidFilling(object):\n    def __init__(self):\n        self.label = \"Dem Void Filling\"\n        self.description = \"This tool can be used to fill the void areas of a DEM using another fill DEM data set.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        fill = arcpy.Parameter(\n            displayName=\"Input Fill DEM\",\n            name=\"fill\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output DEM\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        mean_plane_dist = arcpy.Parameter(\n            displayName=\"Mean-Plane Distance (in grid cells)\",\n            name=\"mean_plane_dist\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        mean_plane_dist.value = '20'\n\n        edge_treatment = arcpy.Parameter(\n            displayName=\"Void-Edge Treatment\",\n            name=\"edge_treatment\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        edge_treatment.filter.type = \"ValueList\"\n        edge_treatment.filter.list = ['use DEM', 'use fill', 'average']\n        edge_treatment.value = 'use DEM'\n\n        weight_value = arcpy.Parameter(\n            displayName=\"Interpolation Weight\",\n            name=\"weight_value\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        weight_value.value = '2.0'\n\n        params = [dem, fill, output, mean_plane_dist, edge_treatment, weight_value]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        fill = parameters[1].valueAsText\n        if fill is not None:\n            desc = arcpy.Describe(fill)\n            fill = desc.catalogPath\n        output = parameters[2].valueAsText\n        mean_plane_dist = parameters[3].valueAsText\n        edge_treatment = parameters[4].valueAsText\n        weight_value = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.dem_void_filling(dem=dem, fill=fill, output=output, mean_plane_dist=mean_plane_dist, edge_treatment=edge_treatment, weight_value=weight_value)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DepthInSink(object):\n    def __init__(self):\n        self.label = \"Depth In Sink\"\n        self.description = \"Measures the depth of sinks (depressions) in a DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        zero_background = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.depth_in_sink(dem=dem, output=output, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DepthToWater(object):\n    def __init__(self):\n        self.label = \"Depth To Water\"\n        self.description = \"This tool calculates cartographic depth-to-water (DTW) index.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams Vector\",\n            name=\"streams\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        streams.filter.list = [\"Polyline\"]\n\n        lakes = arcpy.Parameter(\n            displayName=\"Input Lakes Vector\",\n            name=\"lakes\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        lakes.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, streams, lakes, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        lakes = parameters[2].valueAsText\n        if lakes is not None:\n            desc = arcpy.Describe(lakes)\n            lakes = desc.catalogPath\n        output = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.depth_to_water(dem=dem, streams=streams, lakes=lakes, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DevFromMeanElev(object):\n    def __init__(self):\n        self.label = \"Dev From Mean Elev\"\n        self.description = \"Calculates deviation from mean elevation.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [dem, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.dev_from_mean_elev(dem=dem, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DiffFromMeanElev(object):\n    def __init__(self):\n        self.label = \"Diff From Mean Elev\"\n        self.description = \"Calculates difference from mean elevation (equivalent to a high-pass filter).\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [dem, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.diff_from_mean_elev(dem=dem, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DiffOfGaussianFilter(object):\n    def __init__(self):\n        self.label = \"Diff Of Gaussian Filter\"\n        self.description = \"Performs a Difference of Gaussian (DoG) filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        sigma1 = arcpy.Parameter(\n            displayName=\"Sigma 1 (pixels)\",\n            name=\"sigma1\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma1.value = '2.0'\n\n        sigma2 = arcpy.Parameter(\n            displayName=\"Sigma 2 (pixels)\",\n            name=\"sigma2\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma2.value = '4.0'\n\n        params = [i, output, sigma1, sigma2]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        sigma1 = parameters[2].valueAsText\n        sigma2 = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.diff_of_gaussian_filter(i=i, output=output, sigma1=sigma1, sigma2=sigma2)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Difference(object):\n    def __init__(self):\n        self.label = \"Difference\"\n        self.description = \"Outputs the features that occur in one of the two vector inputs but not both, i.e. no overlapping features.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        overlay = arcpy.Parameter(\n            displayName=\"Input Overlay Vector File\",\n            name=\"overlay\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, overlay, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        overlay = parameters[1].valueAsText\n        if overlay is not None:\n            desc = arcpy.Describe(overlay)\n            overlay = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.difference(i=i, overlay=overlay, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DifferenceCurvature(object):\n    def __init__(self):\n        self.label = \"Difference Curvature\"\n        self.description = \"This tool calculates difference curvature from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.difference_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DirectDecorrelationStretch(object):\n    def __init__(self):\n        self.label = \"Direct Decorrelation Stretch\"\n        self.description = \"Performs a direct decorrelation stretch enhancement on a colour-composite image of multispectral data.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Colour Composite Image File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        k = arcpy.Parameter(\n            displayName=\"Achromatic Factor (0-1)\",\n            name=\"k\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        k.value = '0.5'\n\n        clip = arcpy.Parameter(\n            displayName=\"Percent to clip the upper tail\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '1.0'\n\n        params = [i, output, k, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        k = parameters[2].valueAsText\n        clip = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.direct_decorrelation_stretch(i=i, output=output, k=k, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DirectionalRelief(object):\n    def __init__(self):\n        self.label = \"Directional Relief\"\n        self.description = \"Calculates relief for cells in an input DEM for a specified direction.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        azimuth = arcpy.Parameter(\n            displayName=\"Azimuth\",\n            name=\"azimuth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        azimuth.value = '0.0'\n\n        max_dist = arcpy.Parameter(\n            displayName=\"Maximum Search Distance\",\n            name=\"max_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, azimuth, max_dist]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        azimuth = parameters[2].valueAsText\n        max_dist = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.directional_relief(dem=dem, output=output, azimuth=azimuth, max_dist=max_dist)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Dissolve(object):\n    def __init__(self):\n        self.label = \"Dissolve\"\n        self.description = \"Removes the interior, or shared, boundaries within a vector polygon coverage.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Dissolve Field Attribute\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        snap = arcpy.Parameter(\n            displayName=\"Snap Tolerance\",\n            name=\"snap\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        snap.value = '0.0'\n\n        params = [i, field, output, snap]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        snap = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.dissolve(i=i, field=field, output=output, snap=snap)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DistanceToOutlet(object):\n    def __init__(self):\n        self.label = \"Distance To Outlet\"\n        self.description = \"Calculates the distance of stream grid cells to the channel network outlet cell.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.distance_to_outlet(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DiversityFilter(object):\n    def __init__(self):\n        self.label = \"Diversity Filter\"\n        self.description = \"Assigns each cell in the output grid the number of different values in a moving window centred on each grid cell in the input raster.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.diversity_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Divide(object):\n    def __init__(self):\n        self.label = \"Divide\"\n        self.description = \"Performs a division operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.divide(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DownslopeDistanceToStream(object):\n    def __init__(self):\n        self.label = \"Downslope Distance To Stream\"\n        self.description = \"Measures distance to the nearest downslope stream cell.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        dinf = arcpy.Parameter(\n            displayName=\"Use the D-infinity flow algorithm instead of D8?\",\n            name=\"dinf\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        dinf.value = 'False'\n\n        params = [dem, streams, output, dinf]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        dinf = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.downslope_distance_to_stream(dem=dem, streams=streams, output=output, dinf=dinf)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DownslopeFlowpathLength(object):\n    def __init__(self):\n        self.label = \"Downslope Flowpath Length\"\n        self.description = \"Calculates the downslope flowpath length from each cell to basin outlet.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        watersheds = arcpy.Parameter(\n            displayName=\"Input Watersheds File (optional)\",\n            name=\"watersheds\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        weights = arcpy.Parameter(\n            displayName=\"Input Weights File (optional)\",\n            name=\"weights\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, watersheds, weights, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        watersheds = parameters[1].valueAsText\n        if watersheds is not None:\n            desc = arcpy.Describe(watersheds)\n            watersheds = desc.catalogPath\n        weights = parameters[2].valueAsText\n        if weights is not None:\n            desc = arcpy.Describe(weights)\n            weights = desc.catalogPath\n        output = parameters[3].valueAsText\n        esri_pntr = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.downslope_flowpath_length(d8_pntr=d8_pntr, watersheds=watersheds, weights=weights, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass DownslopeIndex(object):\n    def __init__(self):\n        self.label = \"Downslope Index\"\n        self.description = \"Calculates the Hjerdt et al. (2004) downslope index.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        drop = arcpy.Parameter(\n            displayName=\"Verical Drop\",\n            name=\"drop\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        drop.value = '2.0'\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['tangent', 'degrees', 'radians', 'distance']\n        out_type.value = 'tangent'\n\n        params = [dem, output, drop, out_type]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        drop = parameters[2].valueAsText\n        out_type = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.downslope_index(dem=dem, output=output, drop=drop, out_type=out_type)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EdgeContamination(object):\n    def __init__(self):\n        self.label = \"Edge Contamination\"\n        self.description = \"Identifies grid cells within an input DEM that may be impacted by edge contamination for hydrological applications.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        flow_type = arcpy.Parameter(\n            displayName=\"Flow Type\",\n            name=\"flow_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        flow_type.filter.type = \"ValueList\"\n        flow_type.filter.list = ['d8', 'mfd', 'dinf']\n        flow_type.value = 'mfd'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        params = [dem, output, flow_type, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        flow_type = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.edge_contamination(dem=dem, output=output, flow_type=flow_type, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EdgeDensity(object):\n    def __init__(self):\n        self.label = \"Edge Density\"\n        self.description = \"Calculates the density of edges, or breaks-in-slope within DEMs.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Size\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '11'\n\n        norm_diff = arcpy.Parameter(\n            displayName=\"Normal Difference Threshold\",\n            name=\"norm_diff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        norm_diff.value = '5.0'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, filter, norm_diff, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        norm_diff = parameters[3].valueAsText\n        zfactor = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.edge_density(dem=dem, output=output, filter=filter, norm_diff=norm_diff, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EdgePreservingMeanFilter(object):\n    def __init__(self):\n        self.label = \"Edge Preserving Mean Filter\"\n        self.description = \"Performs a simple edge-preserving mean filter on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Size\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '11'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Value Difference Threshold\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, output, filter, threshold]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        threshold = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.edge_preserving_mean_filter(i=i, output=output, filter=filter, threshold=threshold)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EdgeProportion(object):\n    def __init__(self):\n        self.label = \"Edge Proportion\"\n        self.description = \"Calculate the proportion of cells in a raster polygon that are edge cells.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        output_text = arcpy.Parameter(\n            displayName=\"Output a text report?\",\n            name=\"output_text\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, output_text]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        output_text = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.edge_proportion(i=i, output=output, output_text=output_text)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ElevAbovePit(object):\n    def __init__(self):\n        self.label = \"Elev Above Pit\"\n        self.description = \"Calculate the elevation of each grid cell above the nearest downstream pit cell or grid edge cell.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.elev_above_pit(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ElevPercentile(object):\n    def __init__(self):\n        self.label = \"Elev Percentile\"\n        self.description = \"Calculates the elevation percentile raster from a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        sig_digits = arcpy.Parameter(\n            displayName=\"Number of Significant Digits\",\n            name=\"sig_digits\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sig_digits.value = '2'\n\n        params = [dem, output, filterx, filtery, sig_digits]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        sig_digits = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.elev_percentile(dem=dem, output=output, filterx=filterx, filtery=filtery, sig_digits=sig_digits)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ElevRelativeToMinMax(object):\n    def __init__(self):\n        self.label = \"Elev Relative To Min Max\"\n        self.description = \"Calculates the elevation of a location relative to the minimum and maximum elevations in a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.elev_relative_to_min_max(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ElevRelativeToWatershedMinMax(object):\n    def __init__(self):\n        self.label = \"Elev Relative To Watershed Min Max\"\n        self.description = \"Calculates the elevation of a location relative to the minimum and maximum elevations in a watershed.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        watersheds = arcpy.Parameter(\n            displayName=\"Input Watersheds File\",\n            name=\"watersheds\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, watersheds, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        watersheds = parameters[1].valueAsText\n        if watersheds is not None:\n            desc = arcpy.Describe(watersheds)\n            watersheds = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.elev_relative_to_watershed_min_max(dem=dem, watersheds=watersheds, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ElevationAboveStream(object):\n    def __init__(self):\n        self.label = \"Elevation Above Stream\"\n        self.description = \"Calculates the elevation of cells above the nearest downslope stream cell.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, streams, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.elevation_above_stream(dem=dem, streams=streams, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ElevationAboveStreamEuclidean(object):\n    def __init__(self):\n        self.label = \"Elevation Above Stream Euclidean\"\n        self.description = \"Calculates the elevation of cells above the nearest (Euclidean distance) stream cell.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, streams, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.elevation_above_stream_euclidean(dem=dem, streams=streams, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EliminateCoincidentPoints(object):\n    def __init__(self):\n        self.label = \"Eliminate Coincident Points\"\n        self.description = \"Removes any coincident, or nearly coincident, points from a vector points file.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Points File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        tolerance = arcpy.Parameter(\n            displayName=\"Distance Tolerance\",\n            name=\"tolerance\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, output, tolerance]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        tolerance = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.eliminate_coincident_points(i=i, output=output, tolerance=tolerance)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ElongationRatio(object):\n    def __init__(self):\n        self.label = \"Elongation Ratio\"\n        self.description = \"Calculates the elongation ratio for vector polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.elongation_ratio(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EmbankmentMapping(object):\n    def __init__(self):\n        self.label = \"Embankment Mapping\"\n        self.description = \"Maps and/or removes road embankments from an input fine-resolution DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        road_vec = arcpy.Parameter(\n            displayName=\"Input Vector Transportation Line File\",\n            name=\"road_vec\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        road_vec.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        search_dist = arcpy.Parameter(\n            displayName=\"Search Distance (in map units)\",\n            name=\"search_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        search_dist.value = '2.5'\n\n        min_road_width = arcpy.Parameter(\n            displayName=\"Minimum Road Width (in map units)\",\n            name=\"min_road_width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        min_road_width.value = '6.0'\n\n        typical_width = arcpy.Parameter(\n            displayName=\"Typical Embankment Width (in map units)\",\n            name=\"typical_width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        typical_width.value = '30.0'\n\n        max_height = arcpy.Parameter(\n            displayName=\"Typical Embankment Max Height (in map units)\",\n            name=\"max_height\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        max_height.value = '2.0'\n\n        max_width = arcpy.Parameter(\n            displayName=\"Embankment Max Width (in map units)\",\n            name=\"max_width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        max_width.value = '60.0'\n\n        max_increment = arcpy.Parameter(\n            displayName=\"Max Upwards Increment (in elevation units)\",\n            name=\"max_increment\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        max_increment.value = '0.05'\n\n        spillout_slope = arcpy.Parameter(\n            displayName=\"Spillout Slope (in map units)\",\n            name=\"spillout_slope\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        spillout_slope.value = '4.0'\n\n        remove_embankments = arcpy.Parameter(\n            displayName=\"Remove mapped embankments?\",\n            name=\"remove_embankments\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        remove_embankments.value = 'False'\n\n        params = [dem, road_vec, output, search_dist, min_road_width, typical_width, max_height, max_width, max_increment, spillout_slope, remove_embankments]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        road_vec = parameters[1].valueAsText\n        if road_vec is not None:\n            desc = arcpy.Describe(road_vec)\n            road_vec = desc.catalogPath\n        output = parameters[2].valueAsText\n        search_dist = parameters[3].valueAsText\n        min_road_width = parameters[4].valueAsText\n        typical_width = parameters[5].valueAsText\n        max_height = parameters[6].valueAsText\n        max_width = parameters[7].valueAsText\n        max_increment = parameters[8].valueAsText\n        spillout_slope = parameters[9].valueAsText\n        remove_embankments = parameters[10].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.embankment_mapping(dem=dem, road_vec=road_vec, output=output, search_dist=search_dist, min_road_width=min_road_width, typical_width=typical_width, max_height=max_height, max_width=max_width, max_increment=max_increment, spillout_slope=spillout_slope, remove_embankments=remove_embankments)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EmbossFilter(object):\n    def __init__(self):\n        self.label = \"Emboss Filter\"\n        self.description = \"Performs an emboss filter on an image, similar to a hillshade operation.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        direction = arcpy.Parameter(\n            displayName=\"Direction\",\n            name=\"direction\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        direction.filter.type = \"ValueList\"\n        direction.filter.list = ['n', 's', 'e', 'w', 'ne', 'se', 'nw', 'sw']\n        direction.value = 'n'\n\n        clip = arcpy.Parameter(\n            displayName=\"Percent to clip the distribution tails\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '0.0'\n\n        params = [i, output, direction, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        direction = parameters[2].valueAsText\n        clip = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.emboss_filter(i=i, output=output, direction=direction, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EqualTo(object):\n    def __init__(self):\n        self.label = \"Equal To\"\n        self.description = \"Performs a equal-to comparison operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.equal_to(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Erase(object):\n    def __init__(self):\n        self.label = \"Erase\"\n        self.description = \"Removes all the features, or parts of features, that overlap with the features of the erase vector polygon.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        erase = arcpy.Parameter(\n            displayName=\"Input Erase Polygon Vector File\",\n            name=\"erase\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        erase.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, erase, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        erase = parameters[1].valueAsText\n        if erase is not None:\n            desc = arcpy.Describe(erase)\n            erase = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.erase(i=i, erase=erase, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ErasePolygonFromLidar(object):\n    def __init__(self):\n        self.label = \"Erase Polygon From Lidar\"\n        self.description = \"Erases (cuts out) a vector polygon or polygons from a LiDAR point cloud.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        polygons = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"polygons\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        polygons.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, polygons, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        polygons = parameters[1].valueAsText\n        if polygons is not None:\n            desc = arcpy.Describe(polygons)\n            polygons = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.erase_polygon_from_lidar(i=i, polygons=polygons, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ErasePolygonFromRaster(object):\n    def __init__(self):\n        self.label = \"Erase Polygon From Raster\"\n        self.description = \"Erases (cuts out) a vector polygon from a raster.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        polygons = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"polygons\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        polygons.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, polygons, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        polygons = parameters[1].valueAsText\n        if polygons is not None:\n            desc = arcpy.Describe(polygons)\n            polygons = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.erase_polygon_from_raster(i=i, polygons=polygons, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EuclideanAllocation(object):\n    def __init__(self):\n        self.label = \"Euclidean Allocation\"\n        self.description = \"Assigns grid cells in the output raster the value of the nearest target cell in the input image, measured by the Shih and Wu (2004) Euclidean distance transform.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.euclidean_allocation(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EuclideanDistance(object):\n    def __init__(self):\n        self.label = \"Euclidean Distance\"\n        self.description = \"Calculates the Shih and Wu (2004) Euclidean distance transform.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.euclidean_distance(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass EvaluateTrainingSites(object):\n    def __init__(self):\n        self.label = \"Evaluate Training Sites\"\n        self.description = \"This tool can be used to inspect the overlap in spectral signatures of training sites for various classes.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Band Images\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        polys = arcpy.Parameter(\n            displayName=\"Input Training Polygons\",\n            name=\"polys\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        polys.filter.list = [\"Polygon\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Class Name Field\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [polys.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File (*.html)\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [inputs, polys, field, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        polys = parameters[1].valueAsText\n        if polys is not None:\n            desc = arcpy.Describe(polys)\n            polys = desc.catalogPath\n        field = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.evaluate_training_sites(inputs=inputs, polys=polys, field=field, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Exp(object):\n    def __init__(self):\n        self.label = \"Exp\"\n        self.description = \"Returns the exponential (base e) of values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.exp(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Exp2(object):\n    def __init__(self):\n        self.label = \"Exp2\"\n        self.description = \"Returns the exponential (base 2) of values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.exp2(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ExportTableToCsv(object):\n    def __init__(self):\n        self.label = \"Export Table To Csv\"\n        self.description = \"Exports an attribute table to a CSV text file.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"csv\"]\n\n        headers = arcpy.Parameter(\n            displayName=\"Export field names as file header?\",\n            name=\"headers\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        headers.value = 'True'\n\n        params = [i, output, headers]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        headers = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.export_table_to_csv(i=i, output=output, headers=headers)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ExposureTowardsWindFlux(object):\n    def __init__(self):\n        self.label = \"Exposure Towards Wind Flux\"\n        self.description = \"Evaluates hydrologic connectivity within a DEM\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        azimuth = arcpy.Parameter(\n            displayName=\"Wind Azimuth (in degrees)\",\n            name=\"azimuth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        max_dist = arcpy.Parameter(\n            displayName=\"Maximum Search Distance\",\n            name=\"max_dist\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        params = [dem, output, azimuth, max_dist, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        azimuth = parameters[2].valueAsText\n        max_dist = parameters[3].valueAsText\n        zfactor = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.exposure_towards_wind_flux(dem=dem, output=output, azimuth=azimuth, max_dist=max_dist, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ExtendVectorLines(object):\n    def __init__(self):\n        self.label = \"Extend Vector Lines\"\n        self.description = \"Extends vector lines by a specified distance.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Lines File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        dist = arcpy.Parameter(\n            displayName=\"Extend Distance\",\n            name=\"dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        extend = arcpy.Parameter(\n            displayName=\"Extend Direction\",\n            name=\"extend\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        extend.filter.type = \"ValueList\"\n        extend.filter.list = ['both ends', 'line start', 'line end']\n        extend.value = 'both ends'\n\n        params = [i, output, dist, extend]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        dist = parameters[2].valueAsText\n        extend = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.extend_vector_lines(i=i, output=output, dist=dist, extend=extend)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ExtractNodes(object):\n    def __init__(self):\n        self.label = \"Extract Nodes\"\n        self.description = \"Converts vector lines or polygons into vertex points.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Points File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.extract_nodes(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ExtractRasterValuesAtPoints(object):\n    def __init__(self):\n        self.label = \"Extract Raster Values At Points\"\n        self.description = \"Extracts the values of raster(s) at vector point locations.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        points = arcpy.Parameter(\n            displayName=\"Input Points File\",\n            name=\"points\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        points.filter.list = [\"Point\"]\n\n        out_text = arcpy.Parameter(\n            displayName=\"Output text?\",\n            name=\"out_text\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_text.value = 'False'\n\n        params = [inputs, points, out_text]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        points = parameters[1].valueAsText\n        if points is not None:\n            desc = arcpy.Describe(points)\n            points = desc.catalogPath\n        out_text = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.extract_raster_values_at_points(inputs=inputs, points=points, out_text=out_text)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ExtractStreams(object):\n    def __init__(self):\n        self.label = \"Extract Streams\"\n        self.description = \"Extracts stream grid cells from a flow accumulation raster.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        flow_accum = arcpy.Parameter(\n            displayName=\"Input D8 Flow Accumulation File\",\n            name=\"flow_accum\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        threshold = arcpy.Parameter(\n            displayName=\"Channelization Threshold\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [flow_accum, output, threshold, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        flow_accum = parameters[0].valueAsText\n        if flow_accum is not None:\n            desc = arcpy.Describe(flow_accum)\n            flow_accum = desc.catalogPath\n        output = parameters[1].valueAsText\n        threshold = parameters[2].valueAsText\n        zero_background = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.extract_streams(flow_accum=flow_accum, output=output, threshold=threshold, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ExtractValleys(object):\n    def __init__(self):\n        self.label = \"Extract Valleys\"\n        self.description = \"Identifies potential valley bottom grid cells based on local topolography alone.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        variant = arcpy.Parameter(\n            displayName=\"Variant\",\n            name=\"variant\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        variant.filter.type = \"ValueList\"\n        variant.filter.list = ['LQ', 'JandR', 'PandD']\n        variant.value = 'LQ'\n\n        line_thin = arcpy.Parameter(\n            displayName=\"Perform line-thinning?\",\n            name=\"line_thin\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        line_thin.value = 'True'\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Size (Only For Lower Quartile)\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '5'\n\n        params = [dem, output, variant, line_thin, filter]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        variant = parameters[2].valueAsText\n        line_thin = parameters[3].valueAsText\n        filter = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.extract_valleys(dem=dem, output=output, variant=variant, line_thin=line_thin, filter=filter)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Fd8FlowAccumulation(object):\n    def __init__(self):\n        self.label = \"Fd8 Flow Accumulation\"\n        self.description = \"Calculates an FD8 flow accumulation raster from an input DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['cells', 'specific contributing area', 'catchment area']\n        out_type.value = 'specific contributing area'\n\n        exponent = arcpy.Parameter(\n            displayName=\"Exponent Parameter\",\n            name=\"exponent\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        exponent.value = '1.1'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Convergence Threshold (grid cells; blank for none)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip the upper tail by 1%?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, out_type, exponent, threshold, log, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_type = parameters[2].valueAsText\n        exponent = parameters[3].valueAsText\n        threshold = parameters[4].valueAsText\n        log = parameters[5].valueAsText\n        clip = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fd8_flow_accumulation(dem=dem, output=output, out_type=out_type, exponent=exponent, threshold=threshold, log=log, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Fd8Pointer(object):\n    def __init__(self):\n        self.label = \"Fd8 Pointer\"\n        self.description = \"Calculates an FD8 flow pointer raster from an input DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fd8_pointer(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FarthestChannelHead(object):\n    def __init__(self):\n        self.label = \"Farthest Channel Head\"\n        self.description = \"Calculates the distance to the furthest upstream channel head for each stream cell.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.farthest_channel_head(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FastAlmostGaussianFilter(object):\n    def __init__(self):\n        self.label = \"Fast Almost Gaussian Filter\"\n        self.description = \"Performs a fast approximate Gaussian filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        sigma = arcpy.Parameter(\n            displayName=\"Standard Deviation (pixels)\",\n            name=\"sigma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        sigma.value = '1.8'\n\n        params = [i, output, sigma]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        sigma = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fast_almost_gaussian_filter(i=i, output=output, sigma=sigma)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FeaturePreservingSmoothing(object):\n    def __init__(self):\n        self.label = \"Feature Preserving Smoothing\"\n        self.description = \"Reduces short-scale variation in an input DEM using a modified Sun et al. (2007) algorithm.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Size\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '11'\n\n        norm_diff = arcpy.Parameter(\n            displayName=\"Normal Difference Threshold\",\n            name=\"norm_diff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        norm_diff.value = '15.0'\n\n        num_iter = arcpy.Parameter(\n            displayName=\"Iterations\",\n            name=\"num_iter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_iter.value = '3'\n\n        max_diff = arcpy.Parameter(\n            displayName=\"Maximum Elevation Change\",\n            name=\"max_diff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_diff.value = '0.5'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, filter, norm_diff, num_iter, max_diff, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        norm_diff = parameters[3].valueAsText\n        num_iter = parameters[4].valueAsText\n        max_diff = parameters[5].valueAsText\n        zfactor = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.feature_preserving_smoothing(dem=dem, output=output, filter=filter, norm_diff=norm_diff, num_iter=num_iter, max_diff=max_diff, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FetchAnalysis(object):\n    def __init__(self):\n        self.label = \"Fetch Analysis\"\n        self.description = \"Performs an analysis of fetch or upwind distance to an obstacle.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        azimuth = arcpy.Parameter(\n            displayName=\"Azimuth (degrees)\",\n            name=\"azimuth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        azimuth.value = '0.0'\n\n        hgt_inc = arcpy.Parameter(\n            displayName=\"Height Increment Value\",\n            name=\"hgt_inc\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        hgt_inc.value = '0.05'\n\n        params = [dem, output, azimuth, hgt_inc]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        azimuth = parameters[2].valueAsText\n        hgt_inc = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fetch_analysis(dem=dem, output=output, azimuth=azimuth, hgt_inc=hgt_inc)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FillBurn(object):\n    def __init__(self):\n        self.label = \"Fill Burn\"\n        self.description = \"Burns streams into a DEM using the FillBurn (Saunders, 1999) method.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Vector Streams File\",\n            name=\"streams\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        streams.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, streams, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fill_burn(dem=dem, streams=streams, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FillDepressions(object):\n    def __init__(self):\n        self.label = \"Fill Depressions\"\n        self.description = \"Fills all of the depressions in a DEM. Depression breaching should be preferred in most cases.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        fix_flats = arcpy.Parameter(\n            displayName=\"Fix flat areas?\",\n            name=\"fix_flats\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        fix_flats.value = 'True'\n\n        flat_increment = arcpy.Parameter(\n            displayName=\"Flat increment value (z units)\",\n            name=\"flat_increment\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_depth = arcpy.Parameter(\n            displayName=\"Maximum depth (z units)\",\n            name=\"max_depth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, fix_flats, flat_increment, max_depth]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        fix_flats = parameters[2].valueAsText\n        flat_increment = parameters[3].valueAsText\n        max_depth = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fill_depressions(dem=dem, output=output, fix_flats=fix_flats, flat_increment=flat_increment, max_depth=max_depth)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FillDepressionsPlanchonAndDarboux(object):\n    def __init__(self):\n        self.label = \"Fill Depressions Planchon And Darboux\"\n        self.description = \"Fills all of the depressions in a DEM using the Planchon and Darboux (2002) method.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        fix_flats = arcpy.Parameter(\n            displayName=\"Fix flat areas?\",\n            name=\"fix_flats\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        fix_flats.value = 'True'\n\n        flat_increment = arcpy.Parameter(\n            displayName=\"Flat increment value (z units)\",\n            name=\"flat_increment\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, fix_flats, flat_increment]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        fix_flats = parameters[2].valueAsText\n        flat_increment = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fill_depressions_planchon_and_darboux(dem=dem, output=output, fix_flats=fix_flats, flat_increment=flat_increment)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FillDepressionsWangAndLiu(object):\n    def __init__(self):\n        self.label = \"Fill Depressions Wang And Liu\"\n        self.description = \"Fills all of the depressions in a DEM using the Wang and Liu (2006) method. Depression breaching should be preferred in most cases.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        fix_flats = arcpy.Parameter(\n            displayName=\"Fix flat areas?\",\n            name=\"fix_flats\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        fix_flats.value = 'True'\n\n        flat_increment = arcpy.Parameter(\n            displayName=\"Flat increment value (z units)\",\n            name=\"flat_increment\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, fix_flats, flat_increment]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        fix_flats = parameters[2].valueAsText\n        flat_increment = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fill_depressions_wang_and_liu(dem=dem, output=output, fix_flats=fix_flats, flat_increment=flat_increment)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FillMissingData(object):\n    def __init__(self):\n        self.label = \"Fill Missing Data\"\n        self.description = \"Fills NoData holes in a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Dimension\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        filter.value = '11'\n\n        weight = arcpy.Parameter(\n            displayName=\"IDW Weight (Exponent) Value\",\n            name=\"weight\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        weight.value = '2.0'\n\n        no_edges = arcpy.Parameter(\n            displayName=\"Exclude edge-of-raster-connected NoData cells?\",\n            name=\"no_edges\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        no_edges.value = 'True'\n\n        params = [i, output, filter, weight, no_edges]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        weight = parameters[3].valueAsText\n        no_edges = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fill_missing_data(i=i, output=output, filter=filter, weight=weight, no_edges=no_edges)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FillSingleCellPits(object):\n    def __init__(self):\n        self.label = \"Fill Single Cell Pits\"\n        self.description = \"Raises pit cells to the elevation of their lowest neighbour.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fill_single_cell_pits(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FilterLidar(object):\n    def __init__(self):\n        self.label = \"Filter Lidar\"\n        self.description = \"Filters points within a LiDAR point cloud based on point properties.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR Points\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        statement = arcpy.Parameter(\n            displayName=\"Statement:\",\n            name=\"statement\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        params = [i, output, statement]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        statement = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.filter_lidar(i=i, output=output, statement=statement)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FilterLidarClasses(object):\n    def __init__(self):\n        self.label = \"Filter Lidar Classes\"\n        self.description = \"Removes points in a LAS file with certain specified class values.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        exclude_cls = arcpy.Parameter(\n            displayName=\"Exclusion Classes (0-18, based on LAS spec; e.g. 7,18)\",\n            name=\"exclude_cls\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, exclude_cls]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        exclude_cls = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.filter_lidar_classes(i=i, output=output, exclude_cls=exclude_cls)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FilterLidarScanAngles(object):\n    def __init__(self):\n        self.label = \"Filter Lidar Scan Angles\"\n        self.description = \"Removes points in a LAS file with scan angles greater than a threshold.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        threshold = arcpy.Parameter(\n            displayName=\"Threshold (degrees)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, output, threshold]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        threshold = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.filter_lidar_scan_angles(i=i, output=output, threshold=threshold)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FilterRasterFeaturesByArea(object):\n    def __init__(self):\n        self.label = \"Filter Raster Features By Area\"\n        self.description = \"Removes small-area features from a raster.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        threshold = arcpy.Parameter(\n            displayName=\"Area Threshold (grid cells)\",\n            name=\"threshold\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        background = arcpy.Parameter(\n            displayName=\"Background Value\",\n            name=\"background\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        background.filter.type = \"ValueList\"\n        background.filter.list = ['zero', 'nodata']\n        background.value = 'zero'\n\n        params = [i, output, threshold, background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        threshold = parameters[2].valueAsText\n        background = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.filter_raster_features_by_area(i=i, output=output, threshold=threshold, background=background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FindFlightlineEdgePoints(object):\n    def __init__(self):\n        self.label = \"Find Flightline Edge Points\"\n        self.description = \"Identifies points along a flightline's edge in a LAS file.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.find_flightline_edge_points(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FindLowestOrHighestPoints(object):\n    def __init__(self):\n        self.label = \"Find Lowest Or Highest Points\"\n        self.description = \"Locates the lowest and/or highest valued cells in a raster.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Points File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['lowest', 'highest', 'both']\n        out_type.value = 'lowest'\n\n        params = [i, output, out_type]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_type = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.find_lowest_or_highest_points(i=i, output=output, out_type=out_type)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FindMainStem(object):\n    def __init__(self):\n        self.label = \"Find Main Stem\"\n        self.description = \"Finds the main stem, based on stream lengths, of each stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.find_main_stem(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FindNoFlowCells(object):\n    def __init__(self):\n        self.label = \"Find No Flow Cells\"\n        self.description = \"Finds grid cells with no downslope neighbours.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.find_no_flow_cells(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FindParallelFlow(object):\n    def __init__(self):\n        self.label = \"Find Parallel Flow\"\n        self.description = \"Finds areas of parallel flow in D8 flow direction rasters.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [d8_pntr, streams, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.find_parallel_flow(d8_pntr=d8_pntr, streams=streams, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FindPatchOrClassEdgeCells(object):\n    def __init__(self):\n        self.label = \"Find Patch Or Class Edge Cells\"\n        self.description = \"Finds all cells located on the edge of patch or class features.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.find_patch_or_class_edge_cells(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FindRidges(object):\n    def __init__(self):\n        self.label = \"Find Ridges\"\n        self.description = \"Identifies potential ridge and peak grid cells.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        line_thin = arcpy.Parameter(\n            displayName=\"Perform line-thinning?\",\n            name=\"line_thin\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        line_thin.value = 'True'\n\n        params = [dem, output, line_thin]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        line_thin = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.find_ridges(dem=dem, output=output, line_thin=line_thin)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FixDanglingArcs(object):\n    def __init__(self):\n        self.label = \"Fix Dangling Arcs\"\n        self.description = \"This tool fixes undershot and overshot arcs, two common topological errors, in an input vector lines file.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Lines\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Lines\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        dist = arcpy.Parameter(\n            displayName=\"Snap Distance\",\n            name=\"dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        params = [i, output, dist]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        dist = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.fix_dangling_arcs(i=i, output=output, dist=dist)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FlattenLakes(object):\n    def __init__(self):\n        self.label = \"Flatten Lakes\"\n        self.description = \"Flattens lake polygons in a raster DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        lakes = arcpy.Parameter(\n            displayName=\"Input Lakes Vector Polygon File\",\n            name=\"lakes\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        lakes.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, lakes, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        lakes = parameters[1].valueAsText\n        if lakes is not None:\n            desc = arcpy.Describe(lakes)\n            lakes = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.flatten_lakes(dem=dem, lakes=lakes, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FlightlineOverlap(object):\n    def __init__(self):\n        self.label = \"Flightline Overlap\"\n        self.description = \"Reads a LiDAR (LAS) point file and outputs a raster containing the number of overlapping flight-lines in each grid cell.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        params = [i, output, resolution]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        resolution = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.flightline_overlap(i=i, output=output, resolution=resolution)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FlipImage(object):\n    def __init__(self):\n        self.label = \"Flip Image\"\n        self.description = \"Reflects an image in the vertical or horizontal axis.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        direction = arcpy.Parameter(\n            displayName=\"Direction\",\n            name=\"direction\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        direction.filter.type = \"ValueList\"\n        direction.filter.list = ['vertical', 'horizontal', 'both']\n        direction.value = 'vertical'\n\n        params = [i, output, direction]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        direction = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.flip_image(i=i, output=output, direction=direction)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FloodOrder(object):\n    def __init__(self):\n        self.label = \"Flood Order\"\n        self.description = \"Assigns each DEM grid cell its order in the sequence of inundations that are encountered during a search starting from the edges, moving inward at increasing elevations.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.flood_order(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Floor(object):\n    def __init__(self):\n        self.label = \"Floor\"\n        self.description = \"Returns the largest (closest to positive infinity) value that is less than or equal to the values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.floor(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FlowAccumulationFullWorkflow(object):\n    def __init__(self):\n        self.label = \"Flow Accumulation Full Workflow\"\n        self.description = \"Resolves all of the depressions in a DEM, outputting a breached DEM, an aspect-aligned non-divergent flow pointer, and a flow accumulation raster.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_dem = arcpy.Parameter(\n            displayName=\"Output DEM File\",\n            name=\"out_dem\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_dem.filter.list = [\"tif\"]\n\n        out_pntr = arcpy.Parameter(\n            displayName=\"Output Flow Pointer File\",\n            name=\"out_pntr\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_pntr.filter.list = [\"tif\"]\n\n        out_accum = arcpy.Parameter(\n            displayName=\"Output Flow Accumulation File\",\n            name=\"out_accum\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_accum.filter.list = [\"tif\"]\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['Cells', 'Specific Contributing Area', 'Catchment Area']\n        out_type.value = 'Specific Contributing Area'\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip the upper tail by 1%?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [dem, out_dem, out_pntr, out_accum, out_type, log, clip, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        out_dem = parameters[1].valueAsText\n        out_pntr = parameters[2].valueAsText\n        out_accum = parameters[3].valueAsText\n        out_type = parameters[4].valueAsText\n        log = parameters[5].valueAsText\n        clip = parameters[6].valueAsText\n        esri_pntr = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.flow_accumulation_full_workflow(dem=dem, out_dem=out_dem, out_pntr=out_pntr, out_accum=out_accum, out_type=out_type, log=log, clip=clip, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass FlowLengthDiff(object):\n    def __init__(self):\n        self.label = \"Flow Length Diff\"\n        self.description = \"Calculates the local maximum absolute difference in downslope flowpath length, useful in mapping drainage divides and ridges.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        output = parameters[1].valueAsText\n        esri_pntr = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.flow_length_diff(d8_pntr=d8_pntr, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass GammaCorrection(object):\n    def __init__(self):\n        self.label = \"Gamma Correction\"\n        self.description = \"Performs a gamma correction on an input images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        gamma = arcpy.Parameter(\n            displayName=\"Gamma Value\",\n            name=\"gamma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        gamma.value = '0.5'\n\n        params = [i, output, gamma]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        gamma = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.gamma_correction(i=i, output=output, gamma=gamma)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass GaussianContrastStretch(object):\n    def __init__(self):\n        self.label = \"Gaussian Contrast Stretch\"\n        self.description = \"Performs a Gaussian contrast stretch on input images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        num_tones = arcpy.Parameter(\n            displayName=\"Number of Tones\",\n            name=\"num_tones\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_tones.value = '256'\n\n        params = [i, output, num_tones]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        num_tones = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.gaussian_contrast_stretch(i=i, output=output, num_tones=num_tones)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass GaussianCurvature(object):\n    def __init__(self):\n        self.label = \"Gaussian Curvature\"\n        self.description = \"Calculates a mean curvature raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.gaussian_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass GaussianFilter(object):\n    def __init__(self):\n        self.label = \"Gaussian Filter\"\n        self.description = \"Performs a Gaussian filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        sigma = arcpy.Parameter(\n            displayName=\"Standard Deviation (pixels)\",\n            name=\"sigma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        sigma.value = '0.75'\n\n        params = [i, output, sigma]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        sigma = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.gaussian_filter(i=i, output=output, sigma=sigma)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass GaussianScaleSpace(object):\n    def __init__(self):\n        self.label = \"Gaussian Scale Space\"\n        self.description = \"Uses the fast Gaussian approximation algorithm to produce scaled land-surface parameter measurements from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        points = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"points\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        points.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Land-surface Parameter Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        output_zscore = arcpy.Parameter(\n            displayName=\"Output z-Score Raster File\",\n            name=\"output_zscore\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output_zscore.filter.list = [\"tif\"]\n\n        output_scale = arcpy.Parameter(\n            displayName=\"Output Scale Raster File\",\n            name=\"output_scale\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output_scale.filter.list = [\"tif\"]\n\n        sigma = arcpy.Parameter(\n            displayName=\"Starting Scale\",\n            name=\"sigma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        sigma.value = '0.5'\n\n        step = arcpy.Parameter(\n            displayName=\"Step Size\",\n            name=\"step\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step.value = '0.5'\n\n        num_steps = arcpy.Parameter(\n            displayName=\"Number of Steps\",\n            name=\"num_steps\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_steps.value = '10'\n\n        lsp = arcpy.Parameter(\n            displayName=\"Land-surface Parameter to Calculate\",\n            name=\"lsp\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        lsp.filter.type = \"ValueList\"\n        lsp.filter.list = ['AnisotropyLTP', 'Aspect', 'DiffMeanElev', 'Eastness', 'Elevation', 'Hillshade', 'MeanCurvature', 'Northness', 'PlanCurvature', 'ProfileCurvature', 'Ruggedness', 'Slope', 'TanCurvature', 'TotalCurvature']\n        lsp.value = 'Slope'\n\n        z_factor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"z_factor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, points, output, output_zscore, output_scale, sigma, step, num_steps, lsp, z_factor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        points = parameters[1].valueAsText\n        if points is not None:\n            desc = arcpy.Describe(points)\n            points = desc.catalogPath\n        output = parameters[2].valueAsText\n        output_zscore = parameters[3].valueAsText\n        output_scale = parameters[4].valueAsText\n        sigma = parameters[5].valueAsText\n        step = parameters[6].valueAsText\n        num_steps = parameters[7].valueAsText\n        lsp = parameters[8].valueAsText\n        z_factor = parameters[9].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.gaussian_scale_space(dem=dem, points=points, output=output, output_zscore=output_zscore, output_scale=output_scale, sigma=sigma, step=step, num_steps=num_steps, lsp=lsp, z_factor=z_factor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass GeneralizeClassifiedRaster(object):\n    def __init__(self):\n        self.label = \"Generalize Classified Raster\"\n        self.description = \"Generalizes a raster containing class or object features by removing small features.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster Image\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        min_size = arcpy.Parameter(\n            displayName=\"Min. Feature Size (in grid cells)\",\n            name=\"min_size\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_size.value = '4'\n\n        method = arcpy.Parameter(\n            displayName=\"Method\",\n            name=\"method\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        method.filter.type = \"ValueList\"\n        method.filter.list = ['longest', 'largest', 'nearest']\n        method.value = 'longest'\n\n        params = [i, output, min_size, method]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        min_size = parameters[2].valueAsText\n        method = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.generalize_classified_raster(i=i, output=output, min_size=min_size, method=method)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass GeneralizeWithSimilarity(object):\n    def __init__(self):\n        self.label = \"Generalize With Similarity\"\n        self.description = \"Generalizes a raster containing class or object features by removing small features using similarity criteria of neighbouring features.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster Image\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        similarity = arcpy.Parameter(\n            displayName=\"Input Similarity Images\",\n            name=\"similarity\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        similarity.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        min_size = arcpy.Parameter(\n            displayName=\"Min. Feature Size (in grid cells)\",\n            name=\"min_size\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_size.value = '4'\n\n        params = [i, similarity, output, min_size]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        similarity = parameters[1].valueAsText\n        if similarity is not None:\n            items = similarity.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            similarity = \";\".join(items_path)\n        output = parameters[2].valueAsText\n        min_size = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.generalize_with_similarity(i=i, similarity=similarity, output=output, min_size=min_size)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass GeneratingFunction(object):\n    def __init__(self):\n        self.label = \"Generating Function\"\n        self.description = \"This tool calculates generating function from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.generating_function(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Geomorphons(object):\n    def __init__(self):\n        self.label = \"Geomorphons\"\n        self.description = \"Computes geomorphon patterns.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM file.\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output file.\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        search = arcpy.Parameter(\n            displayName=\"Search distance (cells).\",\n            name=\"search\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        search.value = '50'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Flatness threshold (degrees).\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        threshold.value = '0.0'\n\n        fdist = arcpy.Parameter(\n            displayName=\"Flatness distance (cells).\",\n            name=\"fdist\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        fdist.value = '0'\n\n        skip = arcpy.Parameter(\n            displayName=\"Skip distance (cells).\",\n            name=\"skip\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        skip.value = '0'\n\n        forms = arcpy.Parameter(\n            displayName=\"Output forms\",\n            name=\"forms\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        forms.value = 'True'\n\n        residuals = arcpy.Parameter(\n            displayName=\"Analyze residuals\",\n            name=\"residuals\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        residuals.value = 'False'\n\n        params = [dem, output, search, threshold, fdist, skip, forms, residuals]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        search = parameters[2].valueAsText\n        threshold = parameters[3].valueAsText\n        fdist = parameters[4].valueAsText\n        skip = parameters[5].valueAsText\n        forms = parameters[6].valueAsText\n        residuals = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.geomorphons(dem=dem, output=output, search=search, threshold=threshold, fdist=fdist, skip=skip, forms=forms, residuals=residuals)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass GreaterThan(object):\n    def __init__(self):\n        self.label = \"Greater Than\"\n        self.description = \"Performs a greater-than comparison operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        incl_equals = arcpy.Parameter(\n            displayName=\"Perform a greater-than-OR-EQUAL-TO operation?\",\n            name=\"incl_equals\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [input1, input2, output, incl_equals]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        incl_equals = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.greater_than(input1=input1, input2=input2, output=output, incl_equals=incl_equals)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HackStreamOrder(object):\n    def __init__(self):\n        self.label = \"Hack Stream Order\"\n        self.description = \"Assigns the Hack stream order to each tributary in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.hack_stream_order(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HeatMap(object):\n    def __init__(self):\n        self.label = \"Heat Map\"\n        self.description = \"Calculates a heat map, or kernel density estimation (KDE), for an input point set.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Points\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        weight_field = arcpy.Parameter(\n            displayName=\"Weight Field Name (Optional)\",\n            name=\"weight_field\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        bandwidth = arcpy.Parameter(\n            displayName=\"Bandwidth\",\n            name=\"bandwidth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        kernel = arcpy.Parameter(\n            displayName=\"Kernel Type\",\n            name=\"kernel\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        kernel.filter.type = \"ValueList\"\n        kernel.filter.list = ['uniform', 'triangular', 'epanechnikov', 'quartic', 'triweight', 'tricube', 'gaussian', 'cosine', 'logistic', 'sigmoid', 'silverman']\n        kernel.value = 'quartic'\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Output Raster Cell Size (Optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        base = arcpy.Parameter(\n            displayName=\"Base Raster (Optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, weight_field, output, bandwidth, kernel, cell_size, base]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        weight_field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        bandwidth = parameters[3].valueAsText\n        kernel = parameters[4].valueAsText\n        cell_size = parameters[5].valueAsText\n        base = parameters[6].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.heat_map(i=i, weight_field=weight_field, output=output, bandwidth=bandwidth, kernel=kernel, cell_size=cell_size, base=base)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HeightAboveGround(object):\n    def __init__(self):\n        self.label = \"Height Above Ground\"\n        self.description = \"Normalizes a LiDAR point cloud, providing the height above the nearest ground-classified point.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.height_above_ground(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HighPassBilateralFilter(object):\n    def __init__(self):\n        self.label = \"High Pass Bilateral Filter\"\n        self.description = \"Performs a high-pass bilateral filter, by differencing an input image by the bilateral filter by Tomasi and Manduchi (1998).\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        sigma_dist = arcpy.Parameter(\n            displayName=\"Distance Standard Deviation (pixels)\",\n            name=\"sigma_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma_dist.value = '0.75'\n\n        sigma_int = arcpy.Parameter(\n            displayName=\"Intensity Standard Deviation (intensity units)\",\n            name=\"sigma_int\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma_int.value = '1.0'\n\n        params = [i, output, sigma_dist, sigma_int]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        sigma_dist = parameters[2].valueAsText\n        sigma_int = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.high_pass_bilateral_filter(i=i, output=output, sigma_dist=sigma_dist, sigma_int=sigma_int)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HighPassFilter(object):\n    def __init__(self):\n        self.label = \"High Pass Filter\"\n        self.description = \"Performs a high-pass filter on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.high_pass_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HighPassMedianFilter(object):\n    def __init__(self):\n        self.label = \"High Pass Median Filter\"\n        self.description = \"Performs a high pass median filter on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        sig_digits = arcpy.Parameter(\n            displayName=\"Number of Significant Digits\",\n            name=\"sig_digits\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sig_digits.value = '2'\n\n        params = [i, output, filterx, filtery, sig_digits]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        sig_digits = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.high_pass_median_filter(i=i, output=output, filterx=filterx, filtery=filtery, sig_digits=sig_digits)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HighestPosition(object):\n    def __init__(self):\n        self.label = \"Highest Position\"\n        self.description = \"Identifies the stack position of the maximum value within a raster stack on a cell-by-cell basis.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.highest_position(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Hillshade(object):\n    def __init__(self):\n        self.label = \"Hillshade\"\n        self.description = \"Calculates a hillshade raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        azimuth = arcpy.Parameter(\n            displayName=\"Azimuth (degrees)\",\n            name=\"azimuth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        azimuth.value = '315.0'\n\n        altitude = arcpy.Parameter(\n            displayName=\"Altitude (degrees)\",\n            name=\"altitude\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        altitude.value = '30.0'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, azimuth, altitude, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        azimuth = parameters[2].valueAsText\n        altitude = parameters[3].valueAsText\n        zfactor = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.hillshade(dem=dem, output=output, azimuth=azimuth, altitude=altitude, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Hillslopes(object):\n    def __init__(self):\n        self.label = \"Hillslopes\"\n        self.description = \"Identifies the individual hillslopes draining to each link in a stream network.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, streams, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.hillslopes(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HistogramEqualization(object):\n    def __init__(self):\n        self.label = \"Histogram Equalization\"\n        self.description = \"Performs a histogram equalization contrast enhancement on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        num_tones = arcpy.Parameter(\n            displayName=\"Number of Tones\",\n            name=\"num_tones\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_tones.value = '256'\n\n        params = [i, output, num_tones]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        num_tones = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.histogram_equalization(i=i, output=output, num_tones=num_tones)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HistogramMatching(object):\n    def __init__(self):\n        self.label = \"Histogram Matching\"\n        self.description = \"Alters the statistical distribution of a raster image matching it to a specified PDF.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        histo_file = arcpy.Parameter(\n            displayName=\"Input Probability Distribution Function (PDF) Text File\",\n            name=\"histo_file\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, histo_file, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        histo_file = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.histogram_matching(i=i, histo_file=histo_file, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HistogramMatchingTwoImages(object):\n    def __init__(self):\n        self.label = \"Histogram Matching Two Images\"\n        self.description = \"Alters the cumulative distribution function of a raster image to that of another image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File To Modify\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input Reference File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.histogram_matching_two_images(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HoleProportion(object):\n    def __init__(self):\n        self.label = \"Hole Proportion\"\n        self.description = \"Calculates the proportion of the total area of a polygon's holes relative to the area of the polygon's hull.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.hole_proportion(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HorizonAngle(object):\n    def __init__(self):\n        self.label = \"Horizon Angle\"\n        self.description = \"Calculates horizon angle (maximum upwind slope) for each grid cell in an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        azimuth = arcpy.Parameter(\n            displayName=\"Azimuth\",\n            name=\"azimuth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        azimuth.value = '0.0'\n\n        max_dist = arcpy.Parameter(\n            displayName=\"Maximum Search Distance\",\n            name=\"max_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_dist.value = '100.0'\n\n        params = [dem, output, azimuth, max_dist]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        azimuth = parameters[2].valueAsText\n        max_dist = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.horizon_angle(dem=dem, output=output, azimuth=azimuth, max_dist=max_dist)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HorizontalExcessCurvature(object):\n    def __init__(self):\n        self.label = \"Horizontal Excess Curvature\"\n        self.description = \"This tool calculates horizontal excess curvature from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.horizontal_excess_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HortonStreamOrder(object):\n    def __init__(self):\n        self.label = \"Horton Stream Order\"\n        self.description = \"Assigns the Horton stream order to each tributary in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.horton_stream_order(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HydrologicConnectivity(object):\n    def __init__(self):\n        self.label = \"Hydrologic Connectivity\"\n        self.description = \"This tool evaluates hydrologic connectivity within a DEM\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output1 = arcpy.Parameter(\n            displayName=\"Output Downslope Unsaturated Length File\",\n            name=\"output1\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output1.filter.list = [\"tif\"]\n\n        output2 = arcpy.Parameter(\n            displayName=\"Output Upslope Disconnected Saturated Area File\",\n            name=\"output2\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output2.filter.list = [\"tif\"]\n\n        exponent = arcpy.Parameter(\n            displayName=\"Exponent Parameter\",\n            name=\"exponent\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        exponent.value = '1.0'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Convergence Threshold (grid cells; blank for none)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output1, output2, exponent, threshold]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output1 = parameters[1].valueAsText\n        output2 = parameters[2].valueAsText\n        exponent = parameters[3].valueAsText\n        threshold = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.hydrologic_connectivity(dem=dem, output1=output1, output2=output2, exponent=exponent, threshold=threshold)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HypsometricAnalysis(object):\n    def __init__(self):\n        self.label = \"Hypsometric Analysis\"\n        self.description = \"Calculates a hypsometric curve for one or more DEMs.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input DEM Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        watershed = arcpy.Parameter(\n            displayName=\"Input Watershed Files (optional)\",\n            name=\"watershed\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        watershed.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [inputs, watershed, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        watershed = parameters[1].valueAsText\n        if watershed is not None:\n            items = watershed.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            watershed = \";\".join(items_path)\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.hypsometric_analysis(inputs=inputs, watershed=watershed, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass HypsometricallyTintedHillshade(object):\n    def __init__(self):\n        self.label = \"Hypsometrically Tinted Hillshade\"\n        self.description = \"Creates an colour shaded relief image from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        altitude = arcpy.Parameter(\n            displayName=\"Illumination Source Altitude (degrees)\",\n            name=\"altitude\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        altitude.value = '45.0'\n\n        hs_weight = arcpy.Parameter(\n            displayName=\"Hillshade Weight\",\n            name=\"hs_weight\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        hs_weight.value = '0.5'\n\n        brightness = arcpy.Parameter(\n            displayName=\"Brightness\",\n            name=\"brightness\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        brightness.value = '0.5'\n\n        atmospheric = arcpy.Parameter(\n            displayName=\"Atmospheric Effects\",\n            name=\"atmospheric\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        atmospheric.value = '0.0'\n\n        palette = arcpy.Parameter(\n            displayName=\"Palette\",\n            name=\"palette\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        palette.filter.type = \"ValueList\"\n        palette.filter.list = ['atlas', 'high_relief', 'arid', 'soft', 'muted', 'purple', 'viridis', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep']\n        palette.value = 'atlas'\n\n        reverse = arcpy.Parameter(\n            displayName=\"Reverse palette?\",\n            name=\"reverse\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        reverse.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        full_mode = arcpy.Parameter(\n            displayName=\"Full 360-degree hillshade mode?\",\n            name=\"full_mode\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        full_mode.value = 'False'\n\n        params = [dem, output, altitude, hs_weight, brightness, atmospheric, palette, reverse, zfactor, full_mode]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        altitude = parameters[2].valueAsText\n        hs_weight = parameters[3].valueAsText\n        brightness = parameters[4].valueAsText\n        atmospheric = parameters[5].valueAsText\n        palette = parameters[6].valueAsText\n        reverse = parameters[7].valueAsText\n        zfactor = parameters[8].valueAsText\n        full_mode = parameters[9].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.hypsometrically_tinted_hillshade(dem=dem, output=output, altitude=altitude, hs_weight=hs_weight, brightness=brightness, atmospheric=atmospheric, palette=palette, reverse=reverse, zfactor=zfactor, full_mode=full_mode)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass IdwInterpolation(object):\n    def __init__(self):\n        self.label = \"Idw Interpolation\"\n        self.description = \"Interpolates vector points into a raster surface using an inverse-distance weighted scheme.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        use_z = arcpy.Parameter(\n            displayName=\"Use z-coordinate instead of field?\",\n            name=\"use_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_z.value = 'False'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        weight = arcpy.Parameter(\n            displayName=\"IDW Weight (Exponent) Value\",\n            name=\"weight\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        weight.value = '2.0'\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius (map units)\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        min_points = arcpy.Parameter(\n            displayName=\"Min. Number of Points\",\n            name=\"min_points\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, use_z, output, weight, radius, min_points, cell_size, base]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        use_z = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        weight = parameters[4].valueAsText\n        radius = parameters[5].valueAsText\n        min_points = parameters[6].valueAsText\n        cell_size = parameters[7].valueAsText\n        base = parameters[8].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.idw_interpolation(i=i, field=field, use_z=use_z, output=output, weight=weight, radius=radius, min_points=min_points, cell_size=cell_size, base=base)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass IhsToRgb(object):\n    def __init__(self):\n        self.label = \"Ihs To Rgb\"\n        self.description = \"Converts intensity, hue, and saturation (IHS) images into red, green, and blue (RGB) images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        intensity = arcpy.Parameter(\n            displayName=\"Input Intensity File\",\n            name=\"intensity\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        hue = arcpy.Parameter(\n            displayName=\"Input Hue File\",\n            name=\"hue\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        saturation = arcpy.Parameter(\n            displayName=\"Input Saturation File\",\n            name=\"saturation\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        red = arcpy.Parameter(\n            displayName=\"Output Red Band File (optional; only if colour-composite not specified)\",\n            name=\"red\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        red.filter.list = [\"tif\"]\n\n        green = arcpy.Parameter(\n            displayName=\"Output Green Band File (optional; only if colour-composite not specified)\",\n            name=\"green\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        green.filter.list = [\"tif\"]\n\n        blue = arcpy.Parameter(\n            displayName=\"Output Blue Band File (optional; only if colour-composite not specified)\",\n            name=\"blue\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        blue.filter.list = [\"tif\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Colour-Composite File (optional; only if individual bands not specified)\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [intensity, hue, saturation, red, green, blue, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        intensity = parameters[0].valueAsText\n        if intensity is not None:\n            desc = arcpy.Describe(intensity)\n            intensity = desc.catalogPath\n        hue = parameters[1].valueAsText\n        if hue is not None:\n            desc = arcpy.Describe(hue)\n            hue = desc.catalogPath\n        saturation = parameters[2].valueAsText\n        if saturation is not None:\n            desc = arcpy.Describe(saturation)\n            saturation = desc.catalogPath\n        red = parameters[3].valueAsText\n        green = parameters[4].valueAsText\n        blue = parameters[5].valueAsText\n        output = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.ihs_to_rgb(intensity=intensity, hue=hue, saturation=saturation, red=red, green=green, blue=blue, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ImageAutocorrelation(object):\n    def __init__(self):\n        self.label = \"Image Autocorrelation\"\n        self.description = \"Performs Moran's I analysis on two or more input images.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        contiguity = arcpy.Parameter(\n            displayName=\"Contiguity Type\",\n            name=\"contiguity\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        contiguity.filter.type = \"ValueList\"\n        contiguity.filter.list = ['Rook', 'King', 'Bishop']\n        contiguity.value = 'Rook'\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [inputs, contiguity, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        contiguity = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.image_autocorrelation(inputs=inputs, contiguity=contiguity, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ImageCorrelation(object):\n    def __init__(self):\n        self.label = \"Image Correlation\"\n        self.description = \"Performs image correlation on two or more input images.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.image_correlation(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ImageCorrelationNeighbourhoodAnalysis(object):\n    def __init__(self):\n        self.label = \"Image Correlation Neighbourhood Analysis\"\n        self.description = \"Performs image correlation on two input images neighbourhood search windows.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Image 1\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Image 2\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output1 = arcpy.Parameter(\n            displayName=\"Output Correlation File\",\n            name=\"output1\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output1.filter.list = [\"tif\"]\n\n        output2 = arcpy.Parameter(\n            displayName=\"Output Significance File\",\n            name=\"output2\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output2.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Size\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '11'\n\n        stat = arcpy.Parameter(\n            displayName=\"Correlation Statistic Type\",\n            name=\"stat\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        stat.filter.type = \"ValueList\"\n        stat.filter.list = ['pearson', 'kendall', 'spearman']\n        stat.value = 'pearson'\n\n        params = [input1, input2, output1, output2, filter, stat]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output1 = parameters[2].valueAsText\n        output2 = parameters[3].valueAsText\n        filter = parameters[4].valueAsText\n        stat = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.image_correlation_neighbourhood_analysis(input1=input1, input2=input2, output1=output1, output2=output2, filter=filter, stat=stat)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ImageRegression(object):\n    def __init__(self):\n        self.label = \"Image Regression\"\n        self.description = \"Performs image regression analysis on two input images.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Independent Variable (X).\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Dependent Variable (Y).\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Summary Report File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        out_residuals = arcpy.Parameter(\n            displayName=\"Optional Residuals Output File\",\n            name=\"out_residuals\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_residuals.filter.list = [\"tif\"]\n\n        standardize = arcpy.Parameter(\n            displayName=\"Standardize the residuals map?\",\n            name=\"standardize\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        scattergram = arcpy.Parameter(\n            displayName=\"Output scattergram?\",\n            name=\"scattergram\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        num_samples = arcpy.Parameter(\n            displayName=\"Num. Samples For Scattergram\",\n            name=\"num_samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_samples.value = '1000'\n\n        params = [input1, input2, output, out_residuals, standardize, scattergram, num_samples]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        out_residuals = parameters[3].valueAsText\n        standardize = parameters[4].valueAsText\n        scattergram = parameters[5].valueAsText\n        num_samples = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.image_regression(input1=input1, input2=input2, output=output, out_residuals=out_residuals, standardize=standardize, scattergram=scattergram, num_samples=num_samples)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ImageSegmentation(object):\n    def __init__(self):\n        self.label = \"Image Segmentation\"\n        self.description = \"Performs a region-growing based segmentation on a set of multi-spectral images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Band Images\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        threshold = arcpy.Parameter(\n            displayName=\"Distance Threshold (z-scores)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        threshold.value = '0.5'\n\n        steps = arcpy.Parameter(\n            displayName=\"Number of Steps\",\n            name=\"steps\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        steps.value = '10'\n\n        min_area = arcpy.Parameter(\n            displayName=\"Min. Object Area (in grid cells)\",\n            name=\"min_area\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_area.value = '4'\n\n        params = [inputs, output, threshold, steps, min_area]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        threshold = parameters[2].valueAsText\n        steps = parameters[3].valueAsText\n        min_area = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.image_segmentation(inputs=inputs, output=output, threshold=threshold, steps=steps, min_area=min_area)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ImageSlider(object):\n    def __init__(self):\n        self.label = \"Image Slider\"\n        self.description = \"This tool creates an image slider from two input images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Left Input Raster Image\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        palette1 = arcpy.Parameter(\n            displayName=\"Left Image Palette\",\n            name=\"palette1\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        palette1.filter.type = \"ValueList\"\n        palette1.filter.list = ['grey', 'atlas', 'high_relief', 'arid', 'soft', 'muted', 'purple', 'viridi', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep', 'rgb']\n        palette1.value = 'grey'\n\n        reverse1 = arcpy.Parameter(\n            displayName=\"Reverse left image palette?\",\n            name=\"reverse1\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        reverse1.value = 'False'\n\n        label1 = arcpy.Parameter(\n            displayName=\"Left Image Label (blank for none)\",\n            name=\"label1\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        input2 = arcpy.Parameter(\n            displayName=\"Right Input Raster Image\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        palette2 = arcpy.Parameter(\n            displayName=\"Right Image Palette\",\n            name=\"palette2\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        palette2.filter.type = \"ValueList\"\n        palette2.filter.list = ['grey', 'atlas', 'high_relief', 'arid', 'soft', 'muted', 'purple', 'viridi', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep', 'rgb']\n        palette2.value = 'grey'\n\n        reverse2 = arcpy.Parameter(\n            displayName=\"Reverse right image palette?\",\n            name=\"reverse2\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        reverse2.value = 'False'\n\n        label2 = arcpy.Parameter(\n            displayName=\"Right Image Label (blank for none)\",\n            name=\"label2\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        output = arcpy.Parameter(\n            displayName=\"Output File (*.html)\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        height = arcpy.Parameter(\n            displayName=\"Image Height (in pixels)\",\n            name=\"height\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        height.value = '600'\n\n        params = [input1, palette1, reverse1, label1, input2, palette2, reverse2, label2, output, height]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        palette1 = parameters[1].valueAsText\n        reverse1 = parameters[2].valueAsText\n        label1 = parameters[3].valueAsText\n        input2 = parameters[4].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        palette2 = parameters[5].valueAsText\n        reverse2 = parameters[6].valueAsText\n        label2 = parameters[7].valueAsText\n        output = parameters[8].valueAsText\n        height = parameters[9].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.image_slider(input1=input1, palette1=palette1, reverse1=reverse1, label1=label1, input2=input2, palette2=palette2, reverse2=reverse2, label2=label2, output=output, height=height)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ImageStackProfile(object):\n    def __init__(self):\n        self.label = \"Image Stack Profile\"\n        self.description = \"Plots an image stack profile (i.e. signature) for a set of points and multispectral images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        points = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"points\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        points.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [inputs, points, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        points = parameters[1].valueAsText\n        if points is not None:\n            desc = arcpy.Describe(points)\n            points = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.image_stack_profile(inputs=inputs, points=points, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ImpoundmentSizeIndex(object):\n    def __init__(self):\n        self.label = \"Impoundment Size Index\"\n        self.description = \"Calculates the impoundment size resulting from damming a DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_mean = arcpy.Parameter(\n            displayName=\"Output Mean Depth File\",\n            name=\"out_mean\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_mean.filter.list = [\"tif\"]\n\n        out_max = arcpy.Parameter(\n            displayName=\"Output Max. Depth File\",\n            name=\"out_max\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_max.filter.list = [\"tif\"]\n\n        out_volume = arcpy.Parameter(\n            displayName=\"Output Volume File\",\n            name=\"out_volume\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_volume.filter.list = [\"tif\"]\n\n        out_area = arcpy.Parameter(\n            displayName=\"Output Area File\",\n            name=\"out_area\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_area.filter.list = [\"tif\"]\n\n        out_dam_height = arcpy.Parameter(\n            displayName=\"Output Dam Height File\",\n            name=\"out_dam_height\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_dam_height.filter.list = [\"tif\"]\n\n        damlength = arcpy.Parameter(\n            displayName=\"Max dam length (grid cells)\",\n            name=\"damlength\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [dem, out_mean, out_max, out_volume, out_area, out_dam_height, damlength]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        out_mean = parameters[1].valueAsText\n        out_max = parameters[2].valueAsText\n        out_volume = parameters[3].valueAsText\n        out_area = parameters[4].valueAsText\n        out_dam_height = parameters[5].valueAsText\n        damlength = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.impoundment_size_index(dem=dem, out_mean=out_mean, out_max=out_max, out_volume=out_volume, out_area=out_area, out_dam_height=out_dam_height, damlength=damlength)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass InPlaceAdd(object):\n    def __init__(self):\n        self.label = \"In Place Add\"\n        self.description = \"Performs an in-place addition operation (input1 += input2).\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input Raster File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [input1, input2]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.in_place_add(input1=input1, input2=input2)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass InPlaceDivide(object):\n    def __init__(self):\n        self.label = \"In Place Divide\"\n        self.description = \"Performs an in-place division operation (input1 /= input2).\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input Raster File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [input1, input2]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.in_place_divide(input1=input1, input2=input2)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass InPlaceMultiply(object):\n    def __init__(self):\n        self.label = \"In Place Multiply\"\n        self.description = \"Performs an in-place multiplication operation (input1 *= input2).\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input Raster File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [input1, input2]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.in_place_multiply(input1=input1, input2=input2)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass InPlaceSubtract(object):\n    def __init__(self):\n        self.label = \"In Place Subtract\"\n        self.description = \"Performs an in-place subtraction operation (input1 -= input2).\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input Raster File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [input1, input2]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.in_place_subtract(input1=input1, input2=input2)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Increment(object):\n    def __init__(self):\n        self.label = \"Increment\"\n        self.description = \"Increases the values of each grid cell in an input raster by 1.0. (see also InPlaceAdd)\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.increment(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass IndividualTreeDetection(object):\n    def __init__(self):\n        self.label = \"Individual Tree Detection\"\n        self.description = \"Identifies points in a LiDAR point cloud that are associated with the tops of individual trees.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        min_search_radius = arcpy.Parameter(\n            displayName=\"Min. Search Radius\",\n            name=\"min_search_radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        min_search_radius.value = '1.0'\n\n        min_height = arcpy.Parameter(\n            displayName=\"Min. Height\",\n            name=\"min_height\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        min_height.value = '0.0'\n\n        max_search_radius = arcpy.Parameter(\n            displayName=\"Max. Search Radius\",\n            name=\"max_search_radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_height = arcpy.Parameter(\n            displayName=\"Max. Height\",\n            name=\"max_height\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        only_use_veg = arcpy.Parameter(\n            displayName=\"Only use veg. class points?\",\n            name=\"only_use_veg\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        only_use_veg.value = 'False'\n\n        params = [i, output, min_search_radius, min_height, max_search_radius, max_height, only_use_veg]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        min_search_radius = parameters[2].valueAsText\n        min_height = parameters[3].valueAsText\n        max_search_radius = parameters[4].valueAsText\n        max_height = parameters[5].valueAsText\n        only_use_veg = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.individual_tree_detection(i=i, output=output, min_search_radius=min_search_radius, min_height=min_height, max_search_radius=max_search_radius, max_height=max_height, only_use_veg=only_use_veg)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass InsertDams(object):\n    def __init__(self):\n        self.label = \"Insert Dams\"\n        self.description = \"Calculates the impoundment size resulting from damming a DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        dam_pts = arcpy.Parameter(\n            displayName=\"Input Dam Points\",\n            name=\"dam_pts\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        dam_pts.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        damlength = arcpy.Parameter(\n            displayName=\"Max dam length (grid cells)\",\n            name=\"damlength\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [dem, dam_pts, output, damlength]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        dam_pts = parameters[1].valueAsText\n        if dam_pts is not None:\n            desc = arcpy.Describe(dam_pts)\n            dam_pts = desc.catalogPath\n        output = parameters[2].valueAsText\n        damlength = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.insert_dams(dem=dem, dam_pts=dam_pts, output=output, damlength=damlength)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass InstallWbExtension(object):\n    def __init__(self):\n        self.label = \"Install Wb Extension\"\n        self.description = \"Use to install a Whitebox extension product.\"\n        self.category = \"Whitebox Utilities\"\n\n    def getParameterInfo(self):\n        install_extension = arcpy.Parameter(\n            displayName=\"Whitebox Extension Product Name\",\n            name=\"install_extension\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        install_extension.filter.type = \"ValueList\"\n        install_extension.filter.list = ['General Toolset Extension', 'DEM & Spatial Hydrology Extension', 'Lidar & Remote Sensing Extension', 'Agriculture Extension']\n        install_extension.value = 'General Toolset Extension'\n\n        params = [install_extension]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        install_extension = parameters[0].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.install_wb_extension(install_extension=install_extension)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass IntegerDivision(object):\n    def __init__(self):\n        self.label = \"Integer Division\"\n        self.description = \"Performs an integer division operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.integer_division(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass IntegralImage(object):\n    def __init__(self):\n        self.label = \"Integral Image\"\n        self.description = \"Transforms an input image (summed area table) into its integral image equivalent.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.integral_image(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Intersect(object):\n    def __init__(self):\n        self.label = \"Intersect\"\n        self.description = \"Identifies the parts of features in common between two input vector layers.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        overlay = arcpy.Parameter(\n            displayName=\"Input Overlay Vector File\",\n            name=\"overlay\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        snap = arcpy.Parameter(\n            displayName=\"Snap Tolerance\",\n            name=\"snap\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        snap.value = '0.0'\n\n        params = [i, overlay, output, snap]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        overlay = parameters[1].valueAsText\n        if overlay is not None:\n            desc = arcpy.Describe(overlay)\n            overlay = desc.catalogPath\n        output = parameters[2].valueAsText\n        snap = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.intersect(i=i, overlay=overlay, output=output, snap=snap)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass InversePrincipalComponentAnalysis(object):\n    def __init__(self):\n        self.label = \"Inverse Pca\"\n        self.description = \"This tool performs an inverse principal component analysis on a series of input component images.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input PCA Component Images\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        report = arcpy.Parameter(\n            displayName=\"Input PCA Report File\",\n            name=\"report\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        report.filter.list = [\"html\"]\n\n        params = [inputs, report]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        report = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.inverse_principal_component_analysis(inputs=inputs, report=report)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass IsNoData(object):\n    def __init__(self):\n        self.label = \"Is No Data\"\n        self.description = \"Identifies NoData valued pixels in an image.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.is_no_data(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Isobasins(object):\n    def __init__(self):\n        self.label = \"Isobasins\"\n        self.description = \"Divides a landscape into nearly equal sized drainage basins (i.e. watersheds).\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        size = arcpy.Parameter(\n            displayName=\"Target Basin Size (grid cells)\",\n            name=\"size\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        connections = arcpy.Parameter(\n            displayName=\"Output basin upstream-downstream connections?\",\n            name=\"connections\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        connections.value = 'False'\n\n        params = [dem, output, size, connections]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        size = parameters[2].valueAsText\n        connections = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.isobasins(dem=dem, output=output, size=size, connections=connections)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass JensonSnapPourPoints(object):\n    def __init__(self):\n        self.label = \"Jenson Snap Pour Points\"\n        self.description = \"Moves outlet points used to specify points of interest in a watershedding operation to the nearest stream cell.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        pour_pts = arcpy.Parameter(\n            displayName=\"Input Pour Points (Outlet) File\",\n            name=\"pour_pts\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        pour_pts.filter.list = [\"Point\"]\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        snap_dist = arcpy.Parameter(\n            displayName=\"Maximum Snap Distance (map units)\",\n            name=\"snap_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [pour_pts, streams, output, snap_dist]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        pour_pts = parameters[0].valueAsText\n        if pour_pts is not None:\n            desc = arcpy.Describe(pour_pts)\n            pour_pts = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        snap_dist = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.jenson_snap_pour_points(pour_pts=pour_pts, streams=streams, output=output, snap_dist=snap_dist)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass JoinTables(object):\n    def __init__(self):\n        self.label = \"Join Tables\"\n        self.description = \"Merge a vector's attribute table with another table based on a common field.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input Primary Vector File\",\n            name=\"input1\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        pkey = arcpy.Parameter(\n            displayName=\"Primary Key Field\",\n            name=\"pkey\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        pkey.parameterDependencies = [input1.name]\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input Foreign Vector File\",\n            name=\"input2\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        fkey = arcpy.Parameter(\n            displayName=\"Foreign Key Field\",\n            name=\"fkey\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        fkey.parameterDependencies = [input2.name]\n\n        import_field = arcpy.Parameter(\n            displayName=\"Imported Field\",\n            name=\"import_field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        import_field.parameterDependencies = [input2.name]\n\n        params = [input1, pkey, input2, fkey, import_field]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        pkey = parameters[1].valueAsText\n        input2 = parameters[2].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        fkey = parameters[3].valueAsText\n        import_field = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.join_tables(input1=input1, pkey=pkey, input2=input2, fkey=fkey, import_field=import_field)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass KMeansClustering(object):\n    def __init__(self):\n        self.label = \"K Means Clustering\"\n        self.description = \"Performs a k-means clustering operation on a multi-spectral dataset.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_html = arcpy.Parameter(\n            displayName=\"Output HTML Report File\",\n            name=\"out_html\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_html.filter.list = [\"html\"]\n\n        classes = arcpy.Parameter(\n            displayName=\"Num. Classes (k)\",\n            name=\"classes\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        max_iterations = arcpy.Parameter(\n            displayName=\"Max. Iterations\",\n            name=\"max_iterations\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_iterations.value = '10'\n\n        class_change = arcpy.Parameter(\n            displayName=\"Percent Class Change Threshold\",\n            name=\"class_change\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        class_change.value = '2.0'\n\n        initialize = arcpy.Parameter(\n            displayName=\"How to Initialize Cluster Centres?\",\n            name=\"initialize\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        initialize.filter.type = \"ValueList\"\n        initialize.filter.list = ['diagonal', 'random']\n        initialize.value = 'diagonal'\n\n        min_class_size = arcpy.Parameter(\n            displayName=\"Min. Class Size\",\n            name=\"min_class_size\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_class_size.value = '10'\n\n        params = [inputs, output, out_html, classes, max_iterations, class_change, initialize, min_class_size]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        out_html = parameters[2].valueAsText\n        classes = parameters[3].valueAsText\n        max_iterations = parameters[4].valueAsText\n        class_change = parameters[5].valueAsText\n        initialize = parameters[6].valueAsText\n        min_class_size = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.k_means_clustering(inputs=inputs, output=output, out_html=out_html, classes=classes, max_iterations=max_iterations, class_change=class_change, initialize=initialize, min_class_size=min_class_size)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass KNearestMeanFilter(object):\n    def __init__(self):\n        self.label = \"K Nearest Mean Filter\"\n        self.description = \"A k-nearest mean filter is a type of edge-preserving smoothing filter.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        k = arcpy.Parameter(\n            displayName=\"K-value (pixels)\",\n            name=\"k\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        k.value = '5'\n\n        params = [i, output, filterx, filtery, k]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        k = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.k_nearest_mean_filter(i=i, output=output, filterx=filterx, filtery=filtery, k=k)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass KappaIndex(object):\n    def __init__(self):\n        self.label = \"Kappa Index\"\n        self.description = \"Performs a kappa index of agreement (KIA) analysis on two categorical raster files.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input Classification File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input Reference File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.kappa_index(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass KnnClassification(object):\n    def __init__(self):\n        self.label = \"Knn Classification\"\n        self.description = \"Performs a supervised k-nearest neighbour classification using training site polygons/points and predictor rasters.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Predictor Rasters\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        training = arcpy.Parameter(\n            displayName=\"Input Training Polygons/Points\",\n            name=\"training\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        field = arcpy.Parameter(\n            displayName=\"Class Name Field\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [training.name]\n\n        test_proportion = arcpy.Parameter(\n            displayName=\"Test Proportion\",\n            name=\"test_proportion\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        test_proportion.value = '0.2'\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        scaling = arcpy.Parameter(\n            displayName=\"Scaling Method\",\n            name=\"scaling\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        scaling.filter.type = \"ValueList\"\n        scaling.filter.list = ['None', 'Normalize', 'Standardize']\n        scaling.value = 'Normalize'\n\n        k = arcpy.Parameter(\n            displayName=\"Number of Nearest Neighbours, k\",\n            name=\"k\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        k.value = '5'\n\n        clip = arcpy.Parameter(\n            displayName=\"Perform training data clipping?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = 'True'\n\n        params = [inputs, training, field, test_proportion, output, scaling, k, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        training = parameters[1].valueAsText\n        if training is not None:\n            desc = arcpy.Describe(training)\n            training = desc.catalogPath\n        field = parameters[2].valueAsText\n        test_proportion = parameters[3].valueAsText\n        output = parameters[4].valueAsText\n        scaling = parameters[5].valueAsText\n        k = parameters[6].valueAsText\n        clip = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.knn_classification(inputs=inputs, training=training, field=field, test_proportion=test_proportion, output=output, scaling=scaling, k=k, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass KnnRegression(object):\n    def __init__(self):\n        self.label = \"Knn Regression\"\n        self.description = \"Performs a supervised k-nearest neighbour regression using training site points and predictor rasters.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Predictor Rasters\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        scaling = arcpy.Parameter(\n            displayName=\"Scaling Method\",\n            name=\"scaling\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        scaling.filter.type = \"ValueList\"\n        scaling.filter.list = ['None', 'Normalize', 'Standardize']\n        scaling.value = 'Normalize'\n\n        training = arcpy.Parameter(\n            displayName=\"Input Training Points\",\n            name=\"training\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        training.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Response Variable Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [training.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        k = arcpy.Parameter(\n            displayName=\"Number of Nearest Neighbours, k\",\n            name=\"k\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        k.value = '5'\n\n        weight = arcpy.Parameter(\n            displayName=\"Use distance weighting?\",\n            name=\"weight\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        weight.value = 'True'\n\n        test_proportion = arcpy.Parameter(\n            displayName=\"Test Proportion\",\n            name=\"test_proportion\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        test_proportion.value = '0.2'\n\n        params = [inputs, scaling, training, field, output, k, weight, test_proportion]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        scaling = parameters[1].valueAsText\n        training = parameters[2].valueAsText\n        if training is not None:\n            desc = arcpy.Describe(training)\n            training = desc.catalogPath\n        field = parameters[3].valueAsText\n        output = parameters[4].valueAsText\n        k = parameters[5].valueAsText\n        weight = parameters[6].valueAsText\n        test_proportion = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.knn_regression(inputs=inputs, scaling=scaling, training=training, field=field, output=output, k=k, weight=weight, test_proportion=test_proportion)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass KsTestForNormality(object):\n    def __init__(self):\n        self.label = \"Ks Test For Normality\"\n        self.description = \"Evaluates whether the values in a raster are normally distributed.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        num_samples = arcpy.Parameter(\n            displayName=\"Num. Samples (blank for while image)\",\n            name=\"num_samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, num_samples]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        num_samples = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.ks_test_for_normality(i=i, output=output, num_samples=num_samples)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LaplacianFilter(object):\n    def __init__(self):\n        self.label = \"Laplacian Filter\"\n        self.description = \"Performs a Laplacian filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        variant = arcpy.Parameter(\n            displayName=\"Variant\",\n            name=\"variant\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        variant.filter.type = \"ValueList\"\n        variant.filter.list = ['3x3(1)', '3x3(2)', '3x3(3)', '3x3(4)', '5x5(1)', '5x5(2)']\n        variant.value = '3x3(1)'\n\n        clip = arcpy.Parameter(\n            displayName=\"Distribution Tail Clip Amount (%)\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '0.0'\n\n        params = [i, output, variant, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        variant = parameters[2].valueAsText\n        clip = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.laplacian_filter(i=i, output=output, variant=variant, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LaplacianOfGaussianFilter(object):\n    def __init__(self):\n        self.label = \"Laplacian Of Gaussian Filter\"\n        self.description = \"Performs a Laplacian-of-Gaussian (LoG) filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        sigma = arcpy.Parameter(\n            displayName=\"Standard Deviation (Pixels)\",\n            name=\"sigma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma.value = '0.75'\n\n        params = [i, output, sigma]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        sigma = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.laplacian_of_gaussian_filter(i=i, output=output, sigma=sigma)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LasToAscii(object):\n    def __init__(self):\n        self.label = \"Las To Ascii\"\n        self.description = \"Converts one or more LAS files into ASCII text files.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input LiDAR Files\",\n            name=\"inputs\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n        inputs.filter.list = [\"las\", \"zip\"]\n\n        params = [inputs]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.las_to_ascii(inputs=inputs)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LasToLaz(object):\n    def __init__(self):\n        self.label = \"Las To Laz\"\n        self.description = \"This tool converts one or more LAS files into the LAZ format\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LAS File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LAZ File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.las_to_laz(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LasToMultipointShapefile(object):\n    def __init__(self):\n        self.label = \"Las To Multipoint Shapefile\"\n        self.description = \"Converts one or more LAS files into MultipointZ vector Shapefiles. When the input parameter is not specified, the tool grids all LAS files contained within the working directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.las_to_multipoint_shapefile(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LasToShapefile(object):\n    def __init__(self):\n        self.label = \"Las To Shapefile\"\n        self.description = \"Converts one or more LAS files into a vector Shapefile of POINT ShapeType.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.las_to_shapefile(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LasToZlidar(object):\n    def __init__(self):\n        self.label = \"Las To Zlidar\"\n        self.description = \"Converts one or more LAS files into the zlidar compressed LiDAR data format.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input LAS Files\",\n            name=\"inputs\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        inputs.multiValue = True\n        inputs.filter.list = [\"las\", \"zip\"]\n\n        outdir = arcpy.Parameter(\n            displayName=\"Output Directory\",\n            name=\"outdir\",\n            datatype=\"DEFolder\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        compress = arcpy.Parameter(\n            displayName=\"Compression Method\",\n            name=\"compress\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        compress.filter.type = \"ValueList\"\n        compress.filter.list = ['brotli', 'deflate']\n        compress.value = 'brotli'\n\n        level = arcpy.Parameter(\n            displayName=\"Compression Level\",\n            name=\"level\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        level.value = '5'\n\n        params = [inputs, outdir, compress, level]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        outdir = parameters[1].valueAsText\n        compress = parameters[2].valueAsText\n        level = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.las_to_zlidar(inputs=inputs, outdir=outdir, compress=compress, level=level)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LaunchWbRunner(object):\n    def __init__(self):\n        self.label = \"Launch Wb Runner\"\n        self.description = \"Opens the Whitebox Runner application.\"\n        self.category = \"Whitebox Utilities\"\n\n    def getParameterInfo(self):\n        clear_app_state = arcpy.Parameter(\n            displayName=\"Clear the application state memory?\",\n            name=\"clear_app_state\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clear_app_state.value = 'False'\n\n        params = [clear_app_state]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        clear_app_state = parameters[0].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.launch_wb_runner(clear_app_state=clear_app_state)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LayerFootprint(object):\n    def __init__(self):\n        self.label = \"Layer Footprint\"\n        self.description = \"Creates a vector polygon footprint of the area covered by a raster grid or vector layer.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster or Vector File\",\n            name=\"i\",\n            datatype=[\"DERasterDataset\", \"DEShapefile\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.layer_footprint(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LazToLas(object):\n    def __init__(self):\n        self.label = \"Laz To Las\"\n        self.description = \"This tool converts one or more LAZ files into the LAS format\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LAZ File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LAS File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.laz_to_las(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LeeSigmaFilter(object):\n    def __init__(self):\n        self.label = \"Lee Sigma Filter\"\n        self.description = \"Performs a Lee (Sigma) smoothing filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        sigma = arcpy.Parameter(\n            displayName=\"Sigma\",\n            name=\"sigma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma.value = '10.0'\n\n        m = arcpy.Parameter(\n            displayName=\"M-value\",\n            name=\"m\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        m.value = '5.0'\n\n        params = [i, output, filterx, filtery, sigma, m]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        sigma = parameters[4].valueAsText\n        m = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lee_sigma_filter(i=i, output=output, filterx=filterx, filtery=filtery, sigma=sigma, m=m)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LengthOfUpstreamChannels(object):\n    def __init__(self):\n        self.label = \"Length Of Upstream Channels\"\n        self.description = \"Calculates the total length of channels upstream.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.length_of_upstream_channels(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LessThan(object):\n    def __init__(self):\n        self.label = \"Less Than\"\n        self.description = \"Performs a less-than comparison operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        incl_equals = arcpy.Parameter(\n            displayName=\"Perform a less-than-OR-EQUAL-TO operation?\",\n            name=\"incl_equals\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [input1, input2, output, incl_equals]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        incl_equals = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.less_than(input1=input1, input2=input2, output=output, incl_equals=incl_equals)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarBlockMaximum(object):\n    def __init__(self):\n        self.label = \"Lidar Block Maximum\"\n        self.description = \"Creates a block-maximum raster from an input LAS file. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        params = [i, output, resolution]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        resolution = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_block_maximum(i=i, output=output, resolution=resolution)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarBlockMinimum(object):\n    def __init__(self):\n        self.label = \"Lidar Block Minimum\"\n        self.description = \"Creates a block-minimum raster from an input LAS file. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        params = [i, output, resolution]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        resolution = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_block_minimum(i=i, output=output, resolution=resolution)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarClassifySubset(object):\n    def __init__(self):\n        self.label = \"Lidar Classify Subset\"\n        self.description = \"Classifies the values in one LiDAR point cloud that correspond with points in a subset cloud.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        base = arcpy.Parameter(\n            displayName=\"Input Base LiDAR File\",\n            name=\"base\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        base.filter.list = [\"las\", \"zip\"]\n\n        subset = arcpy.Parameter(\n            displayName=\"Input Subset LiDAR File\",\n            name=\"subset\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        subset.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        subset_class = arcpy.Parameter(\n            displayName=\"Subset Point Class Value\",\n            name=\"subset_class\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        nonsubset_class = arcpy.Parameter(\n            displayName=\"Non-Subset Point Class Value (Optional)\",\n            name=\"nonsubset_class\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [base, subset, output, subset_class, nonsubset_class]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        base = parameters[0].valueAsText\n        subset = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        subset_class = parameters[3].valueAsText\n        nonsubset_class = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_classify_subset(base=base, subset=subset, output=output, subset_class=subset_class, nonsubset_class=nonsubset_class)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarColourize(object):\n    def __init__(self):\n        self.label = \"Lidar Colourize\"\n        self.description = \"Adds the red-green-blue colour fields of a LiDAR (LAS) file based on an input image.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        in_lidar = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"in_lidar\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        in_lidar.filter.list = [\"las\", \"zip\"]\n\n        in_image = arcpy.Parameter(\n            displayName=\"Input Colour Image File\",\n            name=\"in_image\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [in_lidar, in_image, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        in_lidar = parameters[0].valueAsText\n        in_image = parameters[1].valueAsText\n        if in_image is not None:\n            desc = arcpy.Describe(in_image)\n            in_image = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_colourize(in_lidar=in_lidar, in_image=in_image, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarContour(object):\n    def __init__(self):\n        self.label = \"Lidar Contour\"\n        self.description = \"This tool creates a vector contour coverage from an input LiDAR point file.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector Lines\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        interval = arcpy.Parameter(\n            displayName=\"Contour Interval\",\n            name=\"interval\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        interval.value = '10.0'\n\n        base = arcpy.Parameter(\n            displayName=\"Base Contour\",\n            name=\"base\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        base.value = '0.0'\n\n        smooth = arcpy.Parameter(\n            displayName=\"Smoothing Filter Size\",\n            name=\"smooth\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        smooth.value = '5'\n\n        parameter = arcpy.Parameter(\n            displayName=\"Interpolation Parameter\",\n            name=\"parameter\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        parameter.filter.type = \"ValueList\"\n        parameter.filter.list = ['elevation', 'intensity', 'user_data']\n        parameter.value = 'elevation'\n\n        returns = arcpy.Parameter(\n            displayName=\"Point Returns Included\",\n            name=\"returns\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        returns.filter.type = \"ValueList\"\n        returns.filter.list = ['all', 'last', 'first']\n        returns.value = 'all'\n\n        exclude_cls = arcpy.Parameter(\n            displayName=\"Exclusion Classes (0-18, based on LAS spec; e.g. 3,4,5,6,7)\",\n            name=\"exclude_cls\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        minz = arcpy.Parameter(\n            displayName=\"Minimum Elevation Value (optional)\",\n            name=\"minz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        maxz = arcpy.Parameter(\n            displayName=\"Maximum Elevation Value (optional)\",\n            name=\"maxz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_triangle_edge_length = arcpy.Parameter(\n            displayName=\"Maximum Triangle Length (optional)\",\n            name=\"max_triangle_edge_length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, interval, base, smooth, parameter, returns, exclude_cls, minz, maxz, max_triangle_edge_length]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        interval = parameters[2].valueAsText\n        base = parameters[3].valueAsText\n        smooth = parameters[4].valueAsText\n        parameter = parameters[5].valueAsText\n        returns = parameters[6].valueAsText\n        exclude_cls = parameters[7].valueAsText\n        minz = parameters[8].valueAsText\n        maxz = parameters[9].valueAsText\n        max_triangle_edge_length = parameters[10].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_contour(i=i, output=output, interval=interval, base=base, smooth=smooth, parameter=parameter, returns=returns, exclude_cls=exclude_cls, minz=minz, maxz=maxz, max_triangle_edge_length=max_triangle_edge_length)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarDigitalSurfaceModel(object):\n    def __init__(self):\n        self.label = \"Lidar Digital Surface Model\"\n        self.description = \"Creates a top-surface digital surface model (DSM) from a LiDAR point cloud.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '0.5'\n\n        minz = arcpy.Parameter(\n            displayName=\"Minimum Elevation Value (optional)\",\n            name=\"minz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        maxz = arcpy.Parameter(\n            displayName=\"Maximum Elevation Value (optional)\",\n            name=\"maxz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_triangle_edge_length = arcpy.Parameter(\n            displayName=\"Maximum Triangle Edge Length (optional)\",\n            name=\"max_triangle_edge_length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, resolution, radius, minz, maxz, max_triangle_edge_length]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        resolution = parameters[2].valueAsText\n        radius = parameters[3].valueAsText\n        minz = parameters[4].valueAsText\n        maxz = parameters[5].valueAsText\n        max_triangle_edge_length = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_digital_surface_model(i=i, output=output, resolution=resolution, radius=radius, minz=minz, maxz=maxz, max_triangle_edge_length=max_triangle_edge_length)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarEigenvalueFeatures(object):\n    def __init__(self):\n        self.label = \"Lidar Eigenvalue Features\"\n        self.description = \"Calculate eigenvalue-based metrics from a LiDAR point cloud.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        num_neighbours = arcpy.Parameter(\n            displayName=\"Number of Neighbours:\",\n            name=\"num_neighbours\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Distance:\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, num_neighbours, radius]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        num_neighbours = parameters[1].valueAsText\n        radius = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_eigenvalue_features(i=i, num_neighbours=num_neighbours, radius=radius)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarElevationSlice(object):\n    def __init__(self):\n        self.label = \"Lidar Elevation Slice\"\n        self.description = \"Outputs all of the points within a LiDAR (LAS) point file that lie between a specified elevation range.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        minz = arcpy.Parameter(\n            displayName=\"Minimum Elevation Value\",\n            name=\"minz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        maxz = arcpy.Parameter(\n            displayName=\"Maximum Elevation Value\",\n            name=\"maxz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        cls = arcpy.Parameter(\n            displayName=\"Retain but reclass points outside the specified elevation range?\",\n            name=\"cls\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        inclassval = arcpy.Parameter(\n            displayName=\"Class Value Assigned to Points Within Range (Optional)\",\n            name=\"inclassval\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        inclassval.value = '2'\n\n        outclassval = arcpy.Parameter(\n            displayName=\"Class Value Assigned to Points Outside Range (Optional)\",\n            name=\"outclassval\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        outclassval.value = '1'\n\n        params = [i, output, minz, maxz, cls, inclassval, outclassval]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        minz = parameters[2].valueAsText\n        maxz = parameters[3].valueAsText\n        cls = parameters[4].valueAsText\n        inclassval = parameters[5].valueAsText\n        outclassval = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_elevation_slice(i=i, output=output, minz=minz, maxz=maxz, cls=cls, inclassval=inclassval, outclassval=outclassval)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarGroundPointFilter(object):\n    def __init__(self):\n        self.label = \"Lidar Ground Point Filter\"\n        self.description = \"Identifies ground points within LiDAR dataset using a slope-based method.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        radius.value = '2.0'\n\n        min_neighbours = arcpy.Parameter(\n            displayName=\"Minimum Number of Neighbours\",\n            name=\"min_neighbours\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_neighbours.value = '0'\n\n        slope_threshold = arcpy.Parameter(\n            displayName=\"Inter-point Slope Threshold\",\n            name=\"slope_threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        slope_threshold.value = '45.0'\n\n        height_threshold = arcpy.Parameter(\n            displayName=\"Off-terrain Point Height Threshold\",\n            name=\"height_threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        height_threshold.value = '1.0'\n\n        classify = arcpy.Parameter(\n            displayName=\"Classify Points\",\n            name=\"classify\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        classify.value = 'True'\n\n        slope_norm = arcpy.Parameter(\n            displayName=\"Perform initial ground slope normalization?\",\n            name=\"slope_norm\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        slope_norm.value = 'True'\n\n        height_above_ground = arcpy.Parameter(\n            displayName=\"Transform output to height above average ground elevation?\",\n            name=\"height_above_ground\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        height_above_ground.value = 'False'\n\n        params = [i, output, radius, min_neighbours, slope_threshold, height_threshold, classify, slope_norm, height_above_ground]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        radius = parameters[2].valueAsText\n        min_neighbours = parameters[3].valueAsText\n        slope_threshold = parameters[4].valueAsText\n        height_threshold = parameters[5].valueAsText\n        classify = parameters[6].valueAsText\n        slope_norm = parameters[7].valueAsText\n        height_above_ground = parameters[8].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_ground_point_filter(i=i, output=output, radius=radius, min_neighbours=min_neighbours, slope_threshold=slope_threshold, height_threshold=height_threshold, classify=classify, slope_norm=slope_norm, height_above_ground=height_above_ground)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarHexBinning(object):\n    def __init__(self):\n        self.label = \"Lidar Hex Binning\"\n        self.description = \"Hex-bins a set of LiDAR points.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        width = arcpy.Parameter(\n            displayName=\"Hexagon Width\",\n            name=\"width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        orientation = arcpy.Parameter(\n            displayName=\"Grid Orientation\",\n            name=\"orientation\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        orientation.filter.type = \"ValueList\"\n        orientation.filter.list = ['horizontal', 'vertical']\n        orientation.value = 'horizontal'\n\n        params = [i, output, width, orientation]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        width = parameters[2].valueAsText\n        orientation = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_hex_binning(i=i, output=output, width=width, orientation=orientation)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarHillshade(object):\n    def __init__(self):\n        self.label = \"Lidar Hillshade\"\n        self.description = \"Calculates a hillshade value for points within a LAS file and stores these data in the RGB field.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        azimuth = arcpy.Parameter(\n            displayName=\"Azimuth (degrees)\",\n            name=\"azimuth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        azimuth.value = '315.0'\n\n        altitude = arcpy.Parameter(\n            displayName=\"Altitude (degrees)\",\n            name=\"altitude\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        altitude.value = '30.0'\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        radius.value = '1.0'\n\n        params = [i, output, azimuth, altitude, radius]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        azimuth = parameters[2].valueAsText\n        altitude = parameters[3].valueAsText\n        radius = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_hillshade(i=i, output=output, azimuth=azimuth, altitude=altitude, radius=radius)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarHistogram(object):\n    def __init__(self):\n        self.label = \"Lidar Histogram\"\n        self.description = \"Creates a histogram of LiDAR data.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        parameter = arcpy.Parameter(\n            displayName=\"Parameter\",\n            name=\"parameter\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        parameter.filter.type = \"ValueList\"\n        parameter.filter.list = ['elevation', 'intensity', 'scan angle', 'class', 'time']\n        parameter.value = 'elevation'\n\n        clip = arcpy.Parameter(\n            displayName=\"Tail Clip Percent\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '1.0'\n\n        params = [i, output, parameter, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        parameter = parameters[2].valueAsText\n        clip = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_histogram(i=i, output=output, parameter=parameter, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarIdwInterpolation(object):\n    def __init__(self):\n        self.label = \"Lidar Idw Interpolation\"\n        self.description = \"Interpolates LAS files using an inverse-distance weighted (IDW) scheme. When the input/output parameters are not specified, the tool interpolates all LAS files contained within the working directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        parameter = arcpy.Parameter(\n            displayName=\"Interpolation Parameter\",\n            name=\"parameter\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        parameter.filter.type = \"ValueList\"\n        parameter.filter.list = ['elevation', 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data']\n        parameter.value = 'elevation'\n\n        returns = arcpy.Parameter(\n            displayName=\"Point Returns Included\",\n            name=\"returns\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        returns.filter.type = \"ValueList\"\n        returns.filter.list = ['all', 'last', 'first']\n        returns.value = 'all'\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        weight = arcpy.Parameter(\n            displayName=\"IDW Weight (Exponent) Value\",\n            name=\"weight\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        weight.value = '1.0'\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '2.5'\n\n        exclude_cls = arcpy.Parameter(\n            displayName=\"Exclusion Classes (0-18, based on LAS spec; e.g. 3,4,5,6,7)\",\n            name=\"exclude_cls\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        minz = arcpy.Parameter(\n            displayName=\"Minimum Elevation Value (optional)\",\n            name=\"minz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        maxz = arcpy.Parameter(\n            displayName=\"Maximum Elevation Value (optional)\",\n            name=\"maxz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, parameter, returns, resolution, weight, radius, exclude_cls, minz, maxz]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        parameter = parameters[2].valueAsText\n        returns = parameters[3].valueAsText\n        resolution = parameters[4].valueAsText\n        weight = parameters[5].valueAsText\n        radius = parameters[6].valueAsText\n        exclude_cls = parameters[7].valueAsText\n        minz = parameters[8].valueAsText\n        maxz = parameters[9].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_idw_interpolation(i=i, output=output, parameter=parameter, returns=returns, resolution=resolution, weight=weight, radius=radius, exclude_cls=exclude_cls, minz=minz, maxz=maxz)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarInfo(object):\n    def __init__(self):\n        self.label = \"Lidar Info\"\n        self.description = \"Prints information about a LiDAR (LAS) dataset, including header, point return frequency, and classification data and information about the variable length records (VLRs) and geokeys.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Summary Report File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        density = arcpy.Parameter(\n            displayName=\"Calculate the average point density and nominal point spacing?\",\n            name=\"density\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        density.value = 'True'\n\n        vlr = arcpy.Parameter(\n            displayName=\"Print the variable length records (VLRs)?\",\n            name=\"vlr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        vlr.value = 'True'\n\n        geokeys = arcpy.Parameter(\n            displayName=\"Print the geokeys?\",\n            name=\"geokeys\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        geokeys.value = 'True'\n\n        params = [i, output, density, vlr, geokeys]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        density = parameters[2].valueAsText\n        vlr = parameters[3].valueAsText\n        geokeys = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_info(i=i, output=output, density=density, vlr=vlr, geokeys=geokeys)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarJoin(object):\n    def __init__(self):\n        self.label = \"Lidar Join\"\n        self.description = \"Joins multiple LiDAR (LAS) files into a single LAS file.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input LiDAR Files\",\n            name=\"inputs\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n        inputs.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_join(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarKappaIndex(object):\n    def __init__(self):\n        self.label = \"Lidar Kappa Index\"\n        self.description = \"Performs a kappa index of agreement (KIA) analysis on the classifications of two LAS files.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input LiDAR File (Classification)\",\n            name=\"input1\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        input1.filter.list = [\"las\", \"zip\"]\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input LiDAR File (Reference)\",\n            name=\"input2\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        input2.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        class_accuracy = arcpy.Parameter(\n            displayName=\"Output Class Accuracy Raster File\",\n            name=\"class_accuracy\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        class_accuracy.filter.list = [\"tif\"]\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        params = [input1, input2, output, class_accuracy, resolution]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        input2 = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        class_accuracy = parameters[3].valueAsText\n        resolution = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_kappa_index(input1=input1, input2=input2, output=output, class_accuracy=class_accuracy, resolution=resolution)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarNearestNeighbourGridding(object):\n    def __init__(self):\n        self.label = \"Lidar Nearest Neighbour Gridding\"\n        self.description = \"Grids LiDAR files using nearest-neighbour scheme. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        parameter = arcpy.Parameter(\n            displayName=\"Interpolation Parameter\",\n            name=\"parameter\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        parameter.filter.type = \"ValueList\"\n        parameter.filter.list = ['elevation', 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data', 'time']\n        parameter.value = 'elevation'\n\n        returns = arcpy.Parameter(\n            displayName=\"Point Returns Included\",\n            name=\"returns\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        returns.filter.type = \"ValueList\"\n        returns.filter.list = ['all', 'last', 'first']\n        returns.value = 'all'\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '2.5'\n\n        exclude_cls = arcpy.Parameter(\n            displayName=\"Exclusion Classes (0-18, based on LAS spec; e.g. 3,4,5,6,7)\",\n            name=\"exclude_cls\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        minz = arcpy.Parameter(\n            displayName=\"Minimum Elevation Value (optional)\",\n            name=\"minz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        maxz = arcpy.Parameter(\n            displayName=\"Maximum Elevation Value (optional)\",\n            name=\"maxz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, parameter, returns, resolution, radius, exclude_cls, minz, maxz]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        parameter = parameters[2].valueAsText\n        returns = parameters[3].valueAsText\n        resolution = parameters[4].valueAsText\n        radius = parameters[5].valueAsText\n        exclude_cls = parameters[6].valueAsText\n        minz = parameters[7].valueAsText\n        maxz = parameters[8].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_nearest_neighbour_gridding(i=i, output=output, parameter=parameter, returns=returns, resolution=resolution, radius=radius, exclude_cls=exclude_cls, minz=minz, maxz=maxz)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarPointDensity(object):\n    def __init__(self):\n        self.label = \"Lidar Point Density\"\n        self.description = \"Calculates the spatial pattern of point density for a LiDAR data set. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        returns = arcpy.Parameter(\n            displayName=\"Point Returns Included\",\n            name=\"returns\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        returns.filter.type = \"ValueList\"\n        returns.filter.list = ['all', 'last', 'first']\n        returns.value = 'all'\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '2.5'\n\n        exclude_cls = arcpy.Parameter(\n            displayName=\"Exclusion Classes (0-18, based on LAS spec; e.g. 3,4,5,6,7)\",\n            name=\"exclude_cls\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        minz = arcpy.Parameter(\n            displayName=\"Minimum Elevation Value (optional)\",\n            name=\"minz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        maxz = arcpy.Parameter(\n            displayName=\"Maximum Elevation Value (optional)\",\n            name=\"maxz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, returns, resolution, radius, exclude_cls, minz, maxz]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        returns = parameters[2].valueAsText\n        resolution = parameters[3].valueAsText\n        radius = parameters[4].valueAsText\n        exclude_cls = parameters[5].valueAsText\n        minz = parameters[6].valueAsText\n        maxz = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_point_density(i=i, output=output, returns=returns, resolution=resolution, radius=radius, exclude_cls=exclude_cls, minz=minz, maxz=maxz)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarPointReturnAnalysis(object):\n    def __init__(self):\n        self.label = \"Lidar Point Return Analysis\"\n        self.description = \"This tool performs a quality control check on the return values of points in a LiDAR file.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR Points\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_point_return_analysis(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarPointStats(object):\n    def __init__(self):\n        self.label = \"Lidar Point Stats\"\n        self.description = \"Creates several rasters summarizing the distribution of LAS point data. When the input/output parameters are not specified, the tool works on all LAS files contained within the working directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        num_points = arcpy.Parameter(\n            displayName=\"Output number of points?\",\n            name=\"num_points\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_points.value = 'True'\n\n        num_pulses = arcpy.Parameter(\n            displayName=\"Output number of pulses?\",\n            name=\"num_pulses\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        avg_points_per_pulse = arcpy.Parameter(\n            displayName=\"Output average number of points per pulse?\",\n            name=\"avg_points_per_pulse\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        avg_points_per_pulse.value = 'True'\n\n        z_range = arcpy.Parameter(\n            displayName=\"Output elevation range?\",\n            name=\"z_range\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        intensity_range = arcpy.Parameter(\n            displayName=\"Output intensity range?\",\n            name=\"intensity_range\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        predom_class = arcpy.Parameter(\n            displayName=\"Output predominant class?\",\n            name=\"predom_class\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, resolution, num_points, num_pulses, avg_points_per_pulse, z_range, intensity_range, predom_class]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        resolution = parameters[1].valueAsText\n        num_points = parameters[2].valueAsText\n        num_pulses = parameters[3].valueAsText\n        avg_points_per_pulse = parameters[4].valueAsText\n        z_range = parameters[5].valueAsText\n        intensity_range = parameters[6].valueAsText\n        predom_class = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_point_stats(i=i, resolution=resolution, num_points=num_points, num_pulses=num_pulses, avg_points_per_pulse=avg_points_per_pulse, z_range=z_range, intensity_range=intensity_range, predom_class=predom_class)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarRansacPlanes(object):\n    def __init__(self):\n        self.label = \"Lidar Ransac Planes\"\n        self.description = \"Performs a RANSAC analysis to identify points within a LiDAR point cloud that belong to linear planes.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '2.0'\n\n        num_iter = arcpy.Parameter(\n            displayName=\"Number of Iterations\",\n            name=\"num_iter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_iter.value = '50'\n\n        num_samples = arcpy.Parameter(\n            displayName=\"Number of Sample Points\",\n            name=\"num_samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_samples.value = '5'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Inlier Threshold\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        threshold.value = '0.35'\n\n        model_size = arcpy.Parameter(\n            displayName=\"Acceptable Model Size\",\n            name=\"model_size\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        model_size.value = '8'\n\n        max_slope = arcpy.Parameter(\n            displayName=\"Maximum Planar Slope\",\n            name=\"max_slope\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_slope.value = '80.0'\n\n        classify = arcpy.Parameter(\n            displayName=\"Classify Points\",\n            name=\"classify\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        classify.value = 'False'\n\n        last_returns = arcpy.Parameter(\n            displayName=\"Last Returns Only\",\n            name=\"last_returns\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        last_returns.value = 'False'\n\n        params = [i, output, radius, num_iter, num_samples, threshold, model_size, max_slope, classify, last_returns]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        radius = parameters[2].valueAsText\n        num_iter = parameters[3].valueAsText\n        num_samples = parameters[4].valueAsText\n        threshold = parameters[5].valueAsText\n        model_size = parameters[6].valueAsText\n        max_slope = parameters[7].valueAsText\n        classify = parameters[8].valueAsText\n        last_returns = parameters[9].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_ransac_planes(i=i, output=output, radius=radius, num_iter=num_iter, num_samples=num_samples, threshold=threshold, model_size=model_size, max_slope=max_slope, classify=classify, last_returns=last_returns)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarRbfInterpolation(object):\n    def __init__(self):\n        self.label = \"Lidar Rbf Interpolation\"\n        self.description = \"Interpolates LAS files using a radial basis function (RBF) scheme. When the input/output parameters are not specified, the tool interpolates all LAS files contained within the working directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        parameter = arcpy.Parameter(\n            displayName=\"Interpolation Parameter\",\n            name=\"parameter\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        parameter.filter.type = \"ValueList\"\n        parameter.filter.list = ['elevation', 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data']\n        parameter.value = 'elevation'\n\n        returns = arcpy.Parameter(\n            displayName=\"Point Returns Included\",\n            name=\"returns\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        returns.filter.type = \"ValueList\"\n        returns.filter.list = ['all', 'last', 'first']\n        returns.value = 'all'\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        num_points = arcpy.Parameter(\n            displayName=\"Number of Points\",\n            name=\"num_points\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_points.value = '20'\n\n        exclude_cls = arcpy.Parameter(\n            displayName=\"Exclusion Classes (0-18, based on LAS spec; e.g. 3,4,5,6,7)\",\n            name=\"exclude_cls\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        minz = arcpy.Parameter(\n            displayName=\"Minimum Elevation Value (optional)\",\n            name=\"minz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        maxz = arcpy.Parameter(\n            displayName=\"Maximum Elevation Value (optional)\",\n            name=\"maxz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        func_type = arcpy.Parameter(\n            displayName=\"Radial Basis Function Type\",\n            name=\"func_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        func_type.filter.type = \"ValueList\"\n        func_type.filter.list = ['ThinPlateSpline', 'PolyHarmonic', 'Gaussian', 'MultiQuadric', 'InverseMultiQuadric']\n        func_type.value = 'ThinPlateSpline'\n\n        poly_order = arcpy.Parameter(\n            displayName=\"Polynomial Order\",\n            name=\"poly_order\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        poly_order.filter.type = \"ValueList\"\n        poly_order.filter.list = ['none', 'constant', 'affine']\n        poly_order.value = 'none'\n\n        weight = arcpy.Parameter(\n            displayName=\"Weight\",\n            name=\"weight\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        weight.value = '5'\n\n        params = [i, output, parameter, returns, resolution, num_points, exclude_cls, minz, maxz, func_type, poly_order, weight]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        parameter = parameters[2].valueAsText\n        returns = parameters[3].valueAsText\n        resolution = parameters[4].valueAsText\n        num_points = parameters[5].valueAsText\n        exclude_cls = parameters[6].valueAsText\n        minz = parameters[7].valueAsText\n        maxz = parameters[8].valueAsText\n        func_type = parameters[9].valueAsText\n        poly_order = parameters[10].valueAsText\n        weight = parameters[11].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_rbf_interpolation(i=i, output=output, parameter=parameter, returns=returns, resolution=resolution, num_points=num_points, exclude_cls=exclude_cls, minz=minz, maxz=maxz, func_type=func_type, poly_order=poly_order, weight=weight)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarRemoveDuplicates(object):\n    def __init__(self):\n        self.label = \"Lidar Remove Duplicates\"\n        self.description = \"Removes duplicate points from a LiDAR data set.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        include_z = arcpy.Parameter(\n            displayName=\"Include z-values in point comparison?\",\n            name=\"include_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        include_z.value = 'False'\n\n        params = [i, output, include_z]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        include_z = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_remove_duplicates(i=i, output=output, include_z=include_z)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarRemoveOutliers(object):\n    def __init__(self):\n        self.label = \"Lidar Remove Outliers\"\n        self.description = \"Removes outliers (high and low points) in a LiDAR point cloud.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '2.0'\n\n        elev_diff = arcpy.Parameter(\n            displayName=\"Max. Elevation Difference\",\n            name=\"elev_diff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        elev_diff.value = '50.0'\n\n        use_median = arcpy.Parameter(\n            displayName=\"Use difference from median elevation?\",\n            name=\"use_median\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        classify = arcpy.Parameter(\n            displayName=\"Classify Points\",\n            name=\"classify\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        classify.value = 'True'\n\n        params = [i, output, radius, elev_diff, use_median, classify]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        radius = parameters[2].valueAsText\n        elev_diff = parameters[3].valueAsText\n        use_median = parameters[4].valueAsText\n        classify = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_remove_outliers(i=i, output=output, radius=radius, elev_diff=elev_diff, use_median=use_median, classify=classify)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarRooftopAnalysis(object):\n    def __init__(self):\n        self.label = \"Lidar Rooftop Analysis\"\n        self.description = \"Identifies roof segments in a LiDAR point cloud.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        buildings = arcpy.Parameter(\n            displayName=\"Input Building Footprint Polygon File\",\n            name=\"buildings\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        buildings.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '2.0'\n\n        num_iter = arcpy.Parameter(\n            displayName=\"Number of Iterations\",\n            name=\"num_iter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_iter.value = '50'\n\n        num_samples = arcpy.Parameter(\n            displayName=\"Number of Sample Points\",\n            name=\"num_samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_samples.value = '10'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Inlier Threshold\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        threshold.value = '0.15'\n\n        model_size = arcpy.Parameter(\n            displayName=\"Acceptable Model Size (points)\",\n            name=\"model_size\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        model_size.value = '15'\n\n        max_slope = arcpy.Parameter(\n            displayName=\"Maximum Planar Slope (degrees)\",\n            name=\"max_slope\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_slope.value = '65.0'\n\n        norm_diff = arcpy.Parameter(\n            displayName=\"Normal Difference Threshold (degrees)\",\n            name=\"norm_diff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        norm_diff.value = '10.0'\n\n        azimuth = arcpy.Parameter(\n            displayName=\"Azimuth (degrees)\",\n            name=\"azimuth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        azimuth.value = '180.0'\n\n        altitude = arcpy.Parameter(\n            displayName=\"Altitude (degrees)\",\n            name=\"altitude\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        altitude.value = '30.0'\n\n        params = [i, buildings, output, radius, num_iter, num_samples, threshold, model_size, max_slope, norm_diff, azimuth, altitude]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        buildings = parameters[1].valueAsText\n        if buildings is not None:\n            desc = arcpy.Describe(buildings)\n            buildings = desc.catalogPath\n        output = parameters[2].valueAsText\n        radius = parameters[3].valueAsText\n        num_iter = parameters[4].valueAsText\n        num_samples = parameters[5].valueAsText\n        threshold = parameters[6].valueAsText\n        model_size = parameters[7].valueAsText\n        max_slope = parameters[8].valueAsText\n        norm_diff = parameters[9].valueAsText\n        azimuth = parameters[10].valueAsText\n        altitude = parameters[11].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_rooftop_analysis(i=i, buildings=buildings, output=output, radius=radius, num_iter=num_iter, num_samples=num_samples, threshold=threshold, model_size=model_size, max_slope=max_slope, norm_diff=norm_diff, azimuth=azimuth, altitude=altitude)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarSegmentation(object):\n    def __init__(self):\n        self.label = \"Lidar Segmentation\"\n        self.description = \"Segments a LiDAR point cloud based on differences in the orientation of fitted planar surfaces and point proximity.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '2.0'\n\n        num_iter = arcpy.Parameter(\n            displayName=\"Number of Iterations\",\n            name=\"num_iter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_iter.value = '50'\n\n        num_samples = arcpy.Parameter(\n            displayName=\"Number of Sample Points\",\n            name=\"num_samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_samples.value = '10'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Inlier Threshold\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        threshold.value = '0.15'\n\n        model_size = arcpy.Parameter(\n            displayName=\"Acceptable Model Size\",\n            name=\"model_size\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        model_size.value = '15'\n\n        max_slope = arcpy.Parameter(\n            displayName=\"Maximum Planar Slope\",\n            name=\"max_slope\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_slope.value = '80.0'\n\n        norm_diff = arcpy.Parameter(\n            displayName=\"Normal Difference Threshold\",\n            name=\"norm_diff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        norm_diff.value = '10.0'\n\n        maxzdiff = arcpy.Parameter(\n            displayName=\"Maximum Elevation Difference Between Points\",\n            name=\"maxzdiff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        maxzdiff.value = '1.0'\n\n        classes = arcpy.Parameter(\n            displayName=\"Don't cross class boundaries?\",\n            name=\"classes\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        classes.value = 'False'\n\n        ground = arcpy.Parameter(\n            displayName=\"Classify largest segment as ground?\",\n            name=\"ground\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        ground.value = 'False'\n\n        params = [i, output, radius, num_iter, num_samples, threshold, model_size, max_slope, norm_diff, maxzdiff, classes, ground]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        radius = parameters[2].valueAsText\n        num_iter = parameters[3].valueAsText\n        num_samples = parameters[4].valueAsText\n        threshold = parameters[5].valueAsText\n        model_size = parameters[6].valueAsText\n        max_slope = parameters[7].valueAsText\n        norm_diff = parameters[8].valueAsText\n        maxzdiff = parameters[9].valueAsText\n        classes = parameters[10].valueAsText\n        ground = parameters[11].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_segmentation(i=i, output=output, radius=radius, num_iter=num_iter, num_samples=num_samples, threshold=threshold, model_size=model_size, max_slope=max_slope, norm_diff=norm_diff, maxzdiff=maxzdiff, classes=classes, ground=ground)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarSegmentationBasedFilter(object):\n    def __init__(self):\n        self.label = \"Lidar Segmentation Based Filter\"\n        self.description = \"Identifies ground points within LiDAR point clouds using a segmentation based approach.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        radius.value = '5.0'\n\n        norm_diff = arcpy.Parameter(\n            displayName=\"Normal Difference Threshold\",\n            name=\"norm_diff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        norm_diff.value = '2.0'\n\n        maxzdiff = arcpy.Parameter(\n            displayName=\"Maximum Elevation Difference Between Points\",\n            name=\"maxzdiff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        maxzdiff.value = '1.0'\n\n        classify = arcpy.Parameter(\n            displayName=\"Classify Points\",\n            name=\"classify\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, radius, norm_diff, maxzdiff, classify]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        radius = parameters[2].valueAsText\n        norm_diff = parameters[3].valueAsText\n        maxzdiff = parameters[4].valueAsText\n        classify = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_segmentation_based_filter(i=i, output=output, radius=radius, norm_diff=norm_diff, maxzdiff=maxzdiff, classify=classify)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarShift(object):\n    def __init__(self):\n        self.label = \"Lidar Shift\"\n        self.description = \"Shifts the x,y,z coordinates of a LiDAR file.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR Points\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        x_shift = arcpy.Parameter(\n            displayName=\"x-shift\",\n            name=\"x_shift\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        y_shift = arcpy.Parameter(\n            displayName=\"y-shift\",\n            name=\"y_shift\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        z_shift = arcpy.Parameter(\n            displayName=\"z-shift\",\n            name=\"z_shift\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        params = [i, output, x_shift, y_shift, z_shift]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        x_shift = parameters[2].valueAsText\n        y_shift = parameters[3].valueAsText\n        z_shift = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_shift(i=i, output=output, x_shift=x_shift, y_shift=y_shift, z_shift=z_shift)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarSibsonInterpolation(object):\n    def __init__(self):\n        self.label = \"Lidar Sibson Interpolation\"\n        self.description = \"This tool interpolates one or more LiDAR tiles using Sibson's natural neighbour method.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        parameter = arcpy.Parameter(\n            displayName=\"Interpolation Parameter\",\n            name=\"parameter\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        parameter.filter.type = \"ValueList\"\n        parameter.filter.list = ['elevation', 'intensity', 'class', 'return_number', 'number_of_returns', 'scan_angle', 'user_data']\n        parameter.value = 'elevation'\n\n        returns = arcpy.Parameter(\n            displayName=\"Point Returns Included\",\n            name=\"returns\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        returns.filter.type = \"ValueList\"\n        returns.filter.list = ['all', 'last', 'first']\n        returns.value = 'all'\n\n        resolution = arcpy.Parameter(\n            displayName=\"Output Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        exclude_cls = arcpy.Parameter(\n            displayName=\"Exclusion Classes (0-18, based on LAS spec; e.g. 3,4,5,6,7)\",\n            name=\"exclude_cls\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        minz = arcpy.Parameter(\n            displayName=\"Minimum Elevation Value (optional)\",\n            name=\"minz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        maxz = arcpy.Parameter(\n            displayName=\"Maximum Elevation Value (optional)\",\n            name=\"maxz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, parameter, returns, resolution, exclude_cls, minz, maxz]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        parameter = parameters[2].valueAsText\n        returns = parameters[3].valueAsText\n        resolution = parameters[4].valueAsText\n        exclude_cls = parameters[5].valueAsText\n        minz = parameters[6].valueAsText\n        maxz = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_sibson_interpolation(i=i, output=output, parameter=parameter, returns=returns, resolution=resolution, exclude_cls=exclude_cls, minz=minz, maxz=maxz)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarTinGridding(object):\n    def __init__(self):\n        self.label = \"Lidar Tin Gridding\"\n        self.description = \"Creates a raster grid based on a Delaunay triangular irregular network (TIN) fitted to LiDAR points.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        parameter = arcpy.Parameter(\n            displayName=\"Interpolation Parameter\",\n            name=\"parameter\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        parameter.filter.type = \"ValueList\"\n        parameter.filter.list = ['elevation', 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data']\n        parameter.value = 'elevation'\n\n        returns = arcpy.Parameter(\n            displayName=\"Point Returns Included\",\n            name=\"returns\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        returns.filter.type = \"ValueList\"\n        returns.filter.list = ['all', 'last', 'first']\n        returns.value = 'all'\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        exclude_cls = arcpy.Parameter(\n            displayName=\"Exclusion Classes (0-18, based on LAS spec; e.g. 3,4,5,6,7)\",\n            name=\"exclude_cls\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        exclude_cls.value = '7,18'\n\n        minz = arcpy.Parameter(\n            displayName=\"Minimum Elevation Value (optional)\",\n            name=\"minz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        maxz = arcpy.Parameter(\n            displayName=\"Maximum Elevation Value (optional)\",\n            name=\"maxz\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_triangle_edge_length = arcpy.Parameter(\n            displayName=\"Maximum Triangle Edge Length (optional)\",\n            name=\"max_triangle_edge_length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, parameter, returns, resolution, exclude_cls, minz, maxz, max_triangle_edge_length]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        parameter = parameters[2].valueAsText\n        returns = parameters[3].valueAsText\n        resolution = parameters[4].valueAsText\n        exclude_cls = parameters[5].valueAsText\n        minz = parameters[6].valueAsText\n        maxz = parameters[7].valueAsText\n        max_triangle_edge_length = parameters[8].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_tin_gridding(i=i, output=output, parameter=parameter, returns=returns, resolution=resolution, exclude_cls=exclude_cls, minz=minz, maxz=maxz, max_triangle_edge_length=max_triangle_edge_length)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarThin(object):\n    def __init__(self):\n        self.label = \"Lidar Thin\"\n        self.description = \"Thins a LiDAR point cloud, reducing point density.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        resolution = arcpy.Parameter(\n            displayName=\"Sample Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '2.0'\n\n        method = arcpy.Parameter(\n            displayName=\"Point Selection Method\",\n            name=\"method\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        method.filter.type = \"ValueList\"\n        method.filter.list = ['first', 'last', 'lowest', 'highest', 'nearest']\n        method.value = 'lowest'\n\n        save_filtered = arcpy.Parameter(\n            displayName=\"Save filtered points to separate file?\",\n            name=\"save_filtered\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        save_filtered.value = 'False'\n\n        params = [i, output, resolution, method, save_filtered]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        resolution = parameters[2].valueAsText\n        method = parameters[3].valueAsText\n        save_filtered = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_thin(i=i, output=output, resolution=resolution, method=method, save_filtered=save_filtered)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarThinHighDensity(object):\n    def __init__(self):\n        self.label = \"Lidar Thin High Density\"\n        self.description = \"Thins points from high density areas within a LiDAR point cloud.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        resolution.value = '1.0'\n\n        density = arcpy.Parameter(\n            displayName=\"Max. Point Density (pts/m^2)\",\n            name=\"density\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        save_filtered = arcpy.Parameter(\n            displayName=\"Save filtered points to separate file?\",\n            name=\"save_filtered\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        save_filtered.value = 'False'\n\n        params = [i, output, resolution, density, save_filtered]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        resolution = parameters[2].valueAsText\n        density = parameters[3].valueAsText\n        save_filtered = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_thin_high_density(i=i, output=output, resolution=resolution, density=density, save_filtered=save_filtered)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarTile(object):\n    def __init__(self):\n        self.label = \"Lidar Tile\"\n        self.description = \"Tiles a LiDAR LAS file into multiple LAS files.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        width = arcpy.Parameter(\n            displayName=\"Tile Width\",\n            name=\"width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        width.value = '1000.0'\n\n        height = arcpy.Parameter(\n            displayName=\"Tile Height\",\n            name=\"height\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        height.value = '1000.0'\n\n        origin_x = arcpy.Parameter(\n            displayName=\"Origin Point X-Coordinate\",\n            name=\"origin_x\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        origin_x.value = '0.0'\n\n        origin_y = arcpy.Parameter(\n            displayName=\"Origin Point Y-Coordinate\",\n            name=\"origin_y\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        origin_y.value = '0.0'\n\n        min_points = arcpy.Parameter(\n            displayName=\"Minimum Number of Tile Points\",\n            name=\"min_points\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_points.value = '2'\n\n        params = [i, width, height, origin_x, origin_y, min_points]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        width = parameters[1].valueAsText\n        height = parameters[2].valueAsText\n        origin_x = parameters[3].valueAsText\n        origin_y = parameters[4].valueAsText\n        min_points = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_tile(i=i, width=width, height=height, origin_x=origin_x, origin_y=origin_y, min_points=min_points)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarTileFootprint(object):\n    def __init__(self):\n        self.label = \"Lidar Tile Footprint\"\n        self.description = \"Creates a vector polygon of the convex hull of a LiDAR point cloud. When the input/output parameters are not specified, the tool works with all LAS files contained within the working directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        hull = arcpy.Parameter(\n            displayName=\"Create Convex Hull Around Points\",\n            name=\"hull\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        hull.value = 'False'\n\n        params = [i, output, hull]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        hull = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_tile_footprint(i=i, output=output, hull=hull)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LidarTophatTransform(object):\n    def __init__(self):\n        self.label = \"Lidar Tophat Transform\"\n        self.description = \"Performs a white top-hat transform on a Lidar dataset; as an estimate of height above ground, this is useful for modelling the vegetation canopy.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        radius.value = '1.0'\n\n        params = [i, output, radius]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        radius = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lidar_tophat_transform(i=i, output=output, radius=radius)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LineDetectionFilter(object):\n    def __init__(self):\n        self.label = \"Line Detection Filter\"\n        self.description = \"Performs a line-detection filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        variant = arcpy.Parameter(\n            displayName=\"Variant\",\n            name=\"variant\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        variant.filter.type = \"ValueList\"\n        variant.filter.list = ['vertical', 'horizontal', '45', '135']\n        variant.value = 'vertical'\n\n        absvals = arcpy.Parameter(\n            displayName=\"Output absolute values?\",\n            name=\"absvals\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        clip = arcpy.Parameter(\n            displayName=\"Distribution Tail Clip Amount (%)\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '0.0'\n\n        params = [i, output, variant, absvals, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        variant = parameters[2].valueAsText\n        absvals = parameters[3].valueAsText\n        clip = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.line_detection_filter(i=i, output=output, variant=variant, absvals=absvals, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LineIntersections(object):\n    def __init__(self):\n        self.label = \"Line Intersections\"\n        self.description = \"Identifies points where the features of two vector line layers intersect.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input Vector Lines File\",\n            name=\"input1\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        input1.filter.list = [\"Polyline\", \"Polygon\"]\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input Vector Lines File\",\n            name=\"input2\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        input2.filter.list = [\"Polyline\", \"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector Point File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.line_intersections(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LineThinning(object):\n    def __init__(self):\n        self.label = \"Line Thinning\"\n        self.description = \"Performs line thinning a on Boolean raster image; intended to be used with the RemoveSpurs tool.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.line_thinning(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LinearityIndex(object):\n    def __init__(self):\n        self.label = \"Linearity Index\"\n        self.description = \"Calculates the linearity index for vector polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.linearity_index(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LinesToPolygons(object):\n    def __init__(self):\n        self.label = \"Lines To Polygons\"\n        self.description = \"Converts vector polylines to polygons.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Line File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lines_to_polygons(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ListUniqueValues(object):\n    def __init__(self):\n        self.label = \"List Unique Values\"\n        self.description = \"Lists the unique values contained in a field within a vector's attribute table.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [i, field, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.list_unique_values(i=i, field=field, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ListUniqueValuesRaster(object):\n    def __init__(self):\n        self.label = \"List Unique Values Raster\"\n        self.description = \"Lists the unique values contained in a field within a vector's attribute table.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.list_unique_values_raster(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Ln(object):\n    def __init__(self):\n        self.label = \"Ln\"\n        self.description = \"Returns the natural logarithm of values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.ln(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LocalHypsometricAnalysis(object):\n    def __init__(self):\n        self.label = \"Local Hypsometric Analysis\"\n        self.description = \"This tool calculates a local, neighbourhood-based hypsometric integral raster.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_mag = arcpy.Parameter(\n            displayName=\"Output Magnitude Raster\",\n            name=\"out_mag\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_mag.filter.list = [\"tif\"]\n\n        out_scale = arcpy.Parameter(\n            displayName=\"Output Scale Raster\",\n            name=\"out_scale\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_scale.filter.list = [\"tif\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_scale.value = '4'\n\n        step = arcpy.Parameter(\n            displayName=\"Base Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step.value = '1'\n\n        num_steps = arcpy.Parameter(\n            displayName=\"Number of Steps\",\n            name=\"num_steps\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_steps.value = '10'\n\n        step_nonlinearity = arcpy.Parameter(\n            displayName=\"Step Nonlinearity\",\n            name=\"step_nonlinearity\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step_nonlinearity.value = '1.0'\n\n        params = [i, out_mag, out_scale, min_scale, step, num_steps, step_nonlinearity]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        out_mag = parameters[1].valueAsText\n        out_scale = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        step = parameters[4].valueAsText\n        num_steps = parameters[5].valueAsText\n        step_nonlinearity = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.local_hypsometric_analysis(i=i, out_mag=out_mag, out_scale=out_scale, min_scale=min_scale, step=step, num_steps=num_steps, step_nonlinearity=step_nonlinearity)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LocalQuadraticRegression(object):\n    def __init__(self):\n        self.label = \"Local Quadratic Regression\"\n        self.description = \"An implementation of the constrained quadratic regression algorithm using a flexible window size described in Wood (1996).\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Edge Length\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '3'\n\n        params = [dem, output, filter]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.local_quadratic_regression(dem=dem, output=output, filter=filter)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Log10(object):\n    def __init__(self):\n        self.label = \"Log10\"\n        self.description = \"Returns the base-10 logarithm of values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.log10(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Log2(object):\n    def __init__(self):\n        self.label = \"Log2\"\n        self.description = \"Returns the base-2 logarithm of values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.log2(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LogisticRegression(object):\n    def __init__(self):\n        self.label = \"Logistic Regression\"\n        self.description = \"Performs a logistic regression analysis using training site polygons/points and predictor rasters.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Predictor Rasters\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        scaling = arcpy.Parameter(\n            displayName=\"Scaling Method\",\n            name=\"scaling\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        scaling.filter.type = \"ValueList\"\n        scaling.filter.list = ['None', 'Normalize', 'Standardize']\n        scaling.value = 'Normalize'\n\n        training = arcpy.Parameter(\n            displayName=\"Input Training Polygons/Points\",\n            name=\"training\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        field = arcpy.Parameter(\n            displayName=\"Class Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [training.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        test_proportion = arcpy.Parameter(\n            displayName=\"Test Proportion\",\n            name=\"test_proportion\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        test_proportion.value = '0.2'\n\n        params = [inputs, scaling, training, field, output, test_proportion]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        scaling = parameters[1].valueAsText\n        training = parameters[2].valueAsText\n        if training is not None:\n            desc = arcpy.Describe(training)\n            training = desc.catalogPath\n        field = parameters[3].valueAsText\n        output = parameters[4].valueAsText\n        test_proportion = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.logistic_regression(inputs=inputs, scaling=scaling, training=training, field=field, output=output, test_proportion=test_proportion)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LongProfile(object):\n    def __init__(self):\n        self.label = \"Long Profile\"\n        self.description = \"Plots the stream longitudinal profiles for one or more rivers.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, streams, dem, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        dem = parameters[2].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[3].valueAsText\n        esri_pntr = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.long_profile(d8_pntr=d8_pntr, streams=streams, dem=dem, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LongProfileFromPoints(object):\n    def __init__(self):\n        self.label = \"Long Profile From Points\"\n        self.description = \"Plots the longitudinal profiles from flow-paths initiating from a set of vector points.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        points = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"points\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        points.filter.list = [\"Point\"]\n\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, points, dem, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        points = parameters[1].valueAsText\n        if points is not None:\n            desc = arcpy.Describe(points)\n            points = desc.catalogPath\n        dem = parameters[2].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[3].valueAsText\n        esri_pntr = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.long_profile_from_points(d8_pntr=d8_pntr, points=points, dem=dem, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LongestFlowpath(object):\n    def __init__(self):\n        self.label = \"Longest Flowpath\"\n        self.description = \"Delineates the longest flowpaths for a group of subbasins or watersheds.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        basins = arcpy.Parameter(\n            displayName=\"Basins File\",\n            name=\"basins\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [dem, basins, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        basins = parameters[1].valueAsText\n        if basins is not None:\n            desc = arcpy.Describe(basins)\n            basins = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.longest_flowpath(dem=dem, basins=basins, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LowPointsOnHeadwaterDivides(object):\n    def __init__(self):\n        self.label = \"Low Points On Headwater Divides\"\n        self.description = \"This tool locates saddle points along ridges within a digital elevation model (DEM)\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams Raster\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [dem, streams, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.low_points_on_headwater_divides(dem=dem, streams=streams, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass LowestPosition(object):\n    def __init__(self):\n        self.label = \"Lowest Position\"\n        self.description = \"Identifies the stack position of the minimum value within a raster stack on a cell-by-cell basis.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.lowest_position(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MdInfFlowAccumulation(object):\n    def __init__(self):\n        self.label = \"Md Inf Flow Accumulation\"\n        self.description = \"Calculates an FD8 flow accumulation raster from an input DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['cells', 'specific contributing area', 'catchment area']\n        out_type.value = 'specific contributing area'\n\n        exponent = arcpy.Parameter(\n            displayName=\"Exponent Parameter\",\n            name=\"exponent\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        exponent.value = '1.1'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Convergence Threshold (grid cells; blank for none)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip the upper tail by 1%?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, out_type, exponent, threshold, log, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_type = parameters[2].valueAsText\n        exponent = parameters[3].valueAsText\n        threshold = parameters[4].valueAsText\n        log = parameters[5].valueAsText\n        clip = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.md_inf_flow_accumulation(dem=dem, output=output, out_type=out_type, exponent=exponent, threshold=threshold, log=log, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MajorityFilter(object):\n    def __init__(self):\n        self.label = \"Majority Filter\"\n        self.description = \"Assigns each cell in the output grid the most frequently occurring value (mode) in a moving window centred on each grid cell in the input raster.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.majority_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MapOffTerrainObjects(object):\n    def __init__(self):\n        self.label = \"Map Off Terrain Objects\"\n        self.description = \"Maps off-terrain objects in a digital elevation model (DEM).\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        max_slope = arcpy.Parameter(\n            displayName=\"Maximum Slope\",\n            name=\"max_slope\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        max_slope.value = '40.0'\n\n        min_size = arcpy.Parameter(\n            displayName=\"Minimum Feature Size\",\n            name=\"min_size\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        min_size.value = '1'\n\n        params = [dem, output, max_slope, min_size]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        max_slope = parameters[2].valueAsText\n        min_size = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.map_off_terrain_objects(dem=dem, output=output, max_slope=max_slope, min_size=min_size)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Max(object):\n    def __init__(self):\n        self.label = \"Max\"\n        self.description = \"Performs a MAX operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxAbsoluteOverlay(object):\n    def __init__(self):\n        self.label = \"Max Absolute Overlay\"\n        self.description = \"Evaluates the maximum absolute value for each grid cell from a stack of input rasters.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_absolute_overlay(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxAnisotropyDev(object):\n    def __init__(self):\n        self.label = \"Max Anisotropy Dev\"\n        self.description = \"Calculates the maximum anisotropy (directionality) in elevation deviation over a range of spatial scales.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_mag = arcpy.Parameter(\n            displayName=\"Output DEVmax Magnitude File\",\n            name=\"out_mag\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_mag.filter.list = [\"tif\"]\n\n        out_scale = arcpy.Parameter(\n            displayName=\"Output DEVmax Scale File\",\n            name=\"out_scale\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_scale.filter.list = [\"tif\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        min_scale.value = '3'\n\n        max_scale = arcpy.Parameter(\n            displayName=\"Maximum Search Neighbourhood Radius (grid cells)\",\n            name=\"max_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        step = arcpy.Parameter(\n            displayName=\"Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        step.value = '2'\n\n        params = [dem, out_mag, out_scale, min_scale, max_scale, step]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        out_mag = parameters[1].valueAsText\n        out_scale = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        max_scale = parameters[4].valueAsText\n        step = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_anisotropy_dev(dem=dem, out_mag=out_mag, out_scale=out_scale, min_scale=min_scale, max_scale=max_scale, step=step)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxAnisotropyDevSignature(object):\n    def __init__(self):\n        self.label = \"Max Anisotropy Dev Signature\"\n        self.description = \"Calculates the anisotropy in deviation from mean for points over a range of spatial scales.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        points = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"points\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        points.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_scale.value = '1'\n\n        max_scale = arcpy.Parameter(\n            displayName=\"Maximum Search Neighbourhood Radius (grid cells)\",\n            name=\"max_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        step = arcpy.Parameter(\n            displayName=\"Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step.value = '1'\n\n        params = [dem, points, output, min_scale, max_scale, step]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        points = parameters[1].valueAsText\n        if points is not None:\n            desc = arcpy.Describe(points)\n            points = desc.catalogPath\n        output = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        max_scale = parameters[4].valueAsText\n        step = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_anisotropy_dev_signature(dem=dem, points=points, output=output, min_scale=min_scale, max_scale=max_scale, step=step)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxBranchLength(object):\n    def __init__(self):\n        self.label = \"Max Branch Length\"\n        self.description = \"Lindsay and Seibert's (2013) branch length index is used to map drainage divides or ridge lines.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, log]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_branch_length(dem=dem, output=output, log=log)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxDifferenceFromMean(object):\n    def __init__(self):\n        self.label = \"Max Difference From Mean\"\n        self.description = \"Calculates the maximum difference from mean elevation over a range of spatial scales.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_mag = arcpy.Parameter(\n            displayName=\"Output DIFFmax Magnitude File\",\n            name=\"out_mag\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_mag.filter.list = [\"tif\"]\n\n        out_scale = arcpy.Parameter(\n            displayName=\"Output DIFFmax Scale File\",\n            name=\"out_scale\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_scale.filter.list = [\"tif\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        max_scale = arcpy.Parameter(\n            displayName=\"Maximum Search Neighbourhood Radius (grid cells)\",\n            name=\"max_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        step = arcpy.Parameter(\n            displayName=\"Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        step.value = '1'\n\n        params = [dem, out_mag, out_scale, min_scale, max_scale, step]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        out_mag = parameters[1].valueAsText\n        out_scale = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        max_scale = parameters[4].valueAsText\n        step = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_difference_from_mean(dem=dem, out_mag=out_mag, out_scale=out_scale, min_scale=min_scale, max_scale=max_scale, step=step)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxDownslopeElevChange(object):\n    def __init__(self):\n        self.label = \"Max Downslope Elev Change\"\n        self.description = \"Calculates the maximum downslope change in elevation between a grid cell and its eight downslope neighbors.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_downslope_elev_change(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxElevDevSignature(object):\n    def __init__(self):\n        self.label = \"Max Elev Dev Signature\"\n        self.description = \"Calculates the maximum elevation deviation over a range of spatial scales and for a set of points.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        points = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"points\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        points.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        max_scale = arcpy.Parameter(\n            displayName=\"Maximum Search Neighbourhood Radius (grid cells)\",\n            name=\"max_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        step = arcpy.Parameter(\n            displayName=\"Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        step.value = '10'\n\n        params = [dem, points, output, min_scale, max_scale, step]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        points = parameters[1].valueAsText\n        if points is not None:\n            desc = arcpy.Describe(points)\n            points = desc.catalogPath\n        output = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        max_scale = parameters[4].valueAsText\n        step = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_elev_dev_signature(dem=dem, points=points, output=output, min_scale=min_scale, max_scale=max_scale, step=step)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxElevationDeviation(object):\n    def __init__(self):\n        self.label = \"Max Elevation Deviation\"\n        self.description = \"Calculates the maximum elevation deviation over a range of spatial scales.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_mag = arcpy.Parameter(\n            displayName=\"Output DEVmax Magnitude File\",\n            name=\"out_mag\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_mag.filter.list = [\"tif\"]\n\n        out_scale = arcpy.Parameter(\n            displayName=\"Output DEVmax Scale File\",\n            name=\"out_scale\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_scale.filter.list = [\"tif\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        max_scale = arcpy.Parameter(\n            displayName=\"Maximum Search Neighbourhood Radius (grid cells)\",\n            name=\"max_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        step = arcpy.Parameter(\n            displayName=\"Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        step.value = '1'\n\n        params = [dem, out_mag, out_scale, min_scale, max_scale, step]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        out_mag = parameters[1].valueAsText\n        out_scale = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        max_scale = parameters[4].valueAsText\n        step = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_elevation_deviation(dem=dem, out_mag=out_mag, out_scale=out_scale, min_scale=min_scale, max_scale=max_scale, step=step)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxOverlay(object):\n    def __init__(self):\n        self.label = \"Max Overlay\"\n        self.description = \"Evaluates the maximum value for each grid cell from a stack of input rasters.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_overlay(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxUpslopeElevChange(object):\n    def __init__(self):\n        self.label = \"Max Upslope Elev Change\"\n        self.description = \"Calculates the maximum upslope change in elevation between a grid cell and its eight downslope neighbors.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_upslope_elev_change(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxUpslopeFlowpathLength(object):\n    def __init__(self):\n        self.label = \"Max Upslope Flowpath Length\"\n        self.description = \"Measures the maximum length of all upslope flowpaths draining each grid cell.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_upslope_flowpath_length(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaxUpslopeValue(object):\n    def __init__(self):\n        self.label = \"Max Upslope Value\"\n        self.description = \"Calculates the maximum upslope value from an input values raster along flowpaths.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        values = arcpy.Parameter(\n            displayName=\"Values Raster File\",\n            name=\"values\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, values, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        values = parameters[1].valueAsText\n        if values is not None:\n            desc = arcpy.Describe(values)\n            values = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.max_upslope_value(dem=dem, values=values, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaximalCurvature(object):\n    def __init__(self):\n        self.label = \"Maximal Curvature\"\n        self.description = \"Calculates a mean curvature raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.maximal_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MaximumFilter(object):\n    def __init__(self):\n        self.label = \"Maximum Filter\"\n        self.description = \"Assigns each cell in the output grid the maximum value in a moving window centred on each grid cell in the input raster.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.maximum_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MeanCurvature(object):\n    def __init__(self):\n        self.label = \"Mean Curvature\"\n        self.description = \"Calculates a mean curvature raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.mean_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MeanFilter(object):\n    def __init__(self):\n        self.label = \"Mean Filter\"\n        self.description = \"Performs a mean filter (low-pass filter) on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '3'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '3'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.mean_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MedianFilter(object):\n    def __init__(self):\n        self.label = \"Median Filter\"\n        self.description = \"Performs a median filter on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        sig_digits = arcpy.Parameter(\n            displayName=\"Number of Significant Digits\",\n            name=\"sig_digits\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sig_digits.value = '2'\n\n        params = [i, output, filterx, filtery, sig_digits]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        sig_digits = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.median_filter(i=i, output=output, filterx=filterx, filtery=filtery, sig_digits=sig_digits)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Medoid(object):\n    def __init__(self):\n        self.label = \"Medoid\"\n        self.description = \"Calculates the medoid for a series of vector features contained in a shapefile.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.medoid(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MergeLineSegments(object):\n    def __init__(self):\n        self.label = \"Merge Line Segments\"\n        self.description = \"Merges vector line segments into larger features.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        snap = arcpy.Parameter(\n            displayName=\"Snap Tolerance\",\n            name=\"snap\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        snap.value = '0.0'\n\n        params = [i, output, snap]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        snap = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.merge_line_segments(i=i, output=output, snap=snap)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MergeTableWithCsv(object):\n    def __init__(self):\n        self.label = \"Merge Table With Csv\"\n        self.description = \"Merge a vector's attribute table with a table contained within a CSV text file.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Primary Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        pkey = arcpy.Parameter(\n            displayName=\"Primary Key Field\",\n            name=\"pkey\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        pkey.parameterDependencies = [i.name]\n\n        csv = arcpy.Parameter(\n            displayName=\"Input CSV File\",\n            name=\"csv\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        csv.filter.list = [\"csv\"]\n\n        fkey = arcpy.Parameter(\n            displayName=\"Foreign Key Field\",\n            name=\"fkey\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        fkey.parameterDependencies = [csv.name]\n\n        import_field = arcpy.Parameter(\n            displayName=\"Imported Field\",\n            name=\"import_field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        import_field.parameterDependencies = [csv.name]\n\n        params = [i, pkey, csv, fkey, import_field]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        pkey = parameters[1].valueAsText\n        csv = parameters[2].valueAsText\n        fkey = parameters[3].valueAsText\n        import_field = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.merge_table_with_csv(i=i, pkey=pkey, csv=csv, fkey=fkey, import_field=import_field)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MergeVectors(object):\n    def __init__(self):\n        self.label = \"Merge Vectors\"\n        self.description = \"Combines two or more input vectors of the same ShapeType creating a single, new output vector.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Vector Files\",\n            name=\"inputs\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.merge_vectors(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Min(object):\n    def __init__(self):\n        self.label = \"Min\"\n        self.description = \"Performs a MIN operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.min(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinAbsoluteOverlay(object):\n    def __init__(self):\n        self.label = \"Min Absolute Overlay\"\n        self.description = \"Evaluates the minimum absolute value for each grid cell from a stack of input rasters.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.min_absolute_overlay(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinDistClassification(object):\n    def __init__(self):\n        self.label = \"Min Dist Classification\"\n        self.description = \"Performs a supervised minimum-distance classification using training site polygons and multi-spectral images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Band Images\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        polys = arcpy.Parameter(\n            displayName=\"Input Training Polygons\",\n            name=\"polys\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        polys.filter.list = [\"Polygon\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Class Name Field\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [polys.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        threshold = arcpy.Parameter(\n            displayName=\"Distance Threshold (z-scores; blank for none)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [inputs, polys, field, output, threshold]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        polys = parameters[1].valueAsText\n        if polys is not None:\n            desc = arcpy.Describe(polys)\n            polys = desc.catalogPath\n        field = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        threshold = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.min_dist_classification(inputs=inputs, polys=polys, field=field, output=output, threshold=threshold)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinDownslopeElevChange(object):\n    def __init__(self):\n        self.label = \"Min Downslope Elev Change\"\n        self.description = \"Calculates the minimum downslope change in elevation between a grid cell and its eight downslope neighbors.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.min_downslope_elev_change(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinMaxContrastStretch(object):\n    def __init__(self):\n        self.label = \"Min Max Contrast Stretch\"\n        self.description = \"Performs a min-max contrast stretch on an input greytone image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        min_val = arcpy.Parameter(\n            displayName=\"Lower Tail Clip Value\",\n            name=\"min_val\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        max_val = arcpy.Parameter(\n            displayName=\"Upper Tail Clip Value\",\n            name=\"max_val\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        num_tones = arcpy.Parameter(\n            displayName=\"Number of Tones\",\n            name=\"num_tones\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_tones.value = '256'\n\n        params = [i, output, min_val, max_val, num_tones]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        min_val = parameters[2].valueAsText\n        max_val = parameters[3].valueAsText\n        num_tones = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.min_max_contrast_stretch(i=i, output=output, min_val=min_val, max_val=max_val, num_tones=num_tones)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinOverlay(object):\n    def __init__(self):\n        self.label = \"Min Overlay\"\n        self.description = \"Evaluates the minimum value for each grid cell from a stack of input rasters.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.min_overlay(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinimalCurvature(object):\n    def __init__(self):\n        self.label = \"Minimal Curvature\"\n        self.description = \"Calculates a mean curvature raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.minimal_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinimumBoundingBox(object):\n    def __init__(self):\n        self.label = \"Minimum Bounding Box\"\n        self.description = \"Creates a vector minimum bounding rectangle around vector features.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        criterion = arcpy.Parameter(\n            displayName=\"Minimization Criterion\",\n            name=\"criterion\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        criterion.filter.type = \"ValueList\"\n        criterion.filter.list = ['area', 'length', 'width', 'perimeter']\n        criterion.value = 'area'\n\n        features = arcpy.Parameter(\n            displayName=\"Find bounding rectangles around each individual feature.\",\n            name=\"features\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        features.value = 'True'\n\n        params = [i, output, criterion, features]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        criterion = parameters[2].valueAsText\n        features = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.minimum_bounding_box(i=i, output=output, criterion=criterion, features=features)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinimumBoundingCircle(object):\n    def __init__(self):\n        self.label = \"Minimum Bounding Circle\"\n        self.description = \"Delineates the minimum bounding circle (i.e. smallest enclosing circle) for a group of vectors.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        features = arcpy.Parameter(\n            displayName=\"Find bounding circle around each individual feature.\",\n            name=\"features\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        features.value = 'True'\n\n        params = [i, output, features]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        features = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.minimum_bounding_circle(i=i, output=output, features=features)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinimumBoundingEnvelope(object):\n    def __init__(self):\n        self.label = \"Minimum Bounding Envelope\"\n        self.description = \"Creates a vector axis-aligned minimum bounding rectangle (envelope) around vector features.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        features = arcpy.Parameter(\n            displayName=\"Find bounding envelop around each individual feature.\",\n            name=\"features\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        features.value = 'True'\n\n        params = [i, output, features]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        features = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.minimum_bounding_envelope(i=i, output=output, features=features)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinimumConvexHull(object):\n    def __init__(self):\n        self.label = \"Minimum Convex Hull\"\n        self.description = \"Creates a vector convex polygon around vector features.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        features = arcpy.Parameter(\n            displayName=\"Find hulls around each individual feature.\",\n            name=\"features\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        features.value = 'True'\n\n        params = [i, output, features]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        features = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.minimum_convex_hull(i=i, output=output, features=features)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MinimumFilter(object):\n    def __init__(self):\n        self.label = \"Minimum Filter\"\n        self.description = \"Assigns each cell in the output grid the minimum value in a moving window centred on each grid cell in the input raster.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.minimum_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ModifiedKMeansClustering(object):\n    def __init__(self):\n        self.label = \"Modified K Means Clustering\"\n        self.description = \"Performs a modified k-means clustering operation on a multi-spectral dataset.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_html = arcpy.Parameter(\n            displayName=\"Output HTML Report File\",\n            name=\"out_html\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_html.filter.list = [\"html\"]\n\n        start_clusters = arcpy.Parameter(\n            displayName=\"Initial Num. of Clusters\",\n            name=\"start_clusters\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        start_clusters.value = '1000'\n\n        merge_dist = arcpy.Parameter(\n            displayName=\"Cluster Merger Distance\",\n            name=\"merge_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_iterations = arcpy.Parameter(\n            displayName=\"Max. Iterations\",\n            name=\"max_iterations\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_iterations.value = '10'\n\n        class_change = arcpy.Parameter(\n            displayName=\"Percent Class Change Threshold\",\n            name=\"class_change\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        class_change.value = '2.0'\n\n        params = [inputs, output, out_html, start_clusters, merge_dist, max_iterations, class_change]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        out_html = parameters[2].valueAsText\n        start_clusters = parameters[3].valueAsText\n        merge_dist = parameters[4].valueAsText\n        max_iterations = parameters[5].valueAsText\n        class_change = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.modified_k_means_clustering(inputs=inputs, output=output, out_html=out_html, start_clusters=start_clusters, merge_dist=merge_dist, max_iterations=max_iterations, class_change=class_change)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ModifyLidar(object):\n    def __init__(self):\n        self.label = \"Modify Lidar\"\n        self.description = \"Modify points within a LiDAR point cloud based on point properties.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR Points\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        statement = arcpy.Parameter(\n            displayName=\"Statement:\",\n            name=\"statement\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        params = [i, output, statement]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        statement = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.modify_lidar(i=i, output=output, statement=statement)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ModifyNoDataValue(object):\n    def __init__(self):\n        self.label = \"Modify No Data Value\"\n        self.description = \"Modifies nodata values in a raster.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        new_value = arcpy.Parameter(\n            displayName=\"New NoData Value\",\n            name=\"new_value\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        new_value.value = '-32768.0'\n\n        params = [i, new_value]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        new_value = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.modify_no_data_value(i=i, new_value=new_value)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Modulo(object):\n    def __init__(self):\n        self.label = \"Modulo\"\n        self.description = \"Performs a modulo operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.modulo(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Mosaic(object):\n    def __init__(self):\n        self.label = \"Mosaic\"\n        self.description = \"Mosaics two or more images together.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        method = arcpy.Parameter(\n            displayName=\"Resampling Method\",\n            name=\"method\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        method.filter.type = \"ValueList\"\n        method.filter.list = ['nn', 'bilinear', 'cc']\n        method.value = 'nn'\n\n        params = [inputs, output, method]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        method = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.mosaic(inputs=inputs, output=output, method=method)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MosaicWithFeathering(object):\n    def __init__(self):\n        self.label = \"Mosaic With Feathering\"\n        self.description = \"Mosaics two images together using a feathering technique in overlapping areas to reduce edge-effects.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File To Modify\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input Reference File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        method = arcpy.Parameter(\n            displayName=\"Resampling Method\",\n            name=\"method\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        method.filter.type = \"ValueList\"\n        method.filter.list = ['nn', 'bilinear', 'cc']\n        method.value = 'cc'\n\n        weight = arcpy.Parameter(\n            displayName=\"Distance Weight\",\n            name=\"weight\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        weight.value = '4.0'\n\n        params = [input1, input2, output, method, weight]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        method = parameters[3].valueAsText\n        weight = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.mosaic_with_feathering(input1=input1, input2=input2, output=output, method=method, weight=weight)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultiPartToSinglePart(object):\n    def __init__(self):\n        self.label = \"Multi Part To Single Part\"\n        self.description = \"Converts a vector file containing multi-part features into a vector containing only single-part features.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Line or Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Line or Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        exclude_holes = arcpy.Parameter(\n            displayName=\"Exclude hole parts?\",\n            name=\"exclude_holes\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        exclude_holes.value = 'True'\n\n        params = [i, output, exclude_holes]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        exclude_holes = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multi_part_to_single_part(i=i, output=output, exclude_holes=exclude_holes)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultidirectionalHillshade(object):\n    def __init__(self):\n        self.label = \"Multidirectional Hillshade\"\n        self.description = \"Calculates a multi-direction hillshade raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        altitude = arcpy.Parameter(\n            displayName=\"Altitude (degrees)\",\n            name=\"altitude\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        altitude.value = '45.0'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        full_mode = arcpy.Parameter(\n            displayName=\"Full 360-degree mode?\",\n            name=\"full_mode\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        full_mode.value = 'False'\n\n        params = [dem, output, altitude, zfactor, full_mode]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        altitude = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        full_mode = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multidirectional_hillshade(dem=dem, output=output, altitude=altitude, zfactor=zfactor, full_mode=full_mode)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Multiply(object):\n    def __init__(self):\n        self.label = \"Multiply\"\n        self.description = \"Performs a multiplication operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multiply(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultiplyOverlay(object):\n    def __init__(self):\n        self.label = \"Multiply Overlay\"\n        self.description = \"Calculates the sum for each grid cell from a group of raster images.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multiply_overlay(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultiscaleCurvatures(object):\n    def __init__(self):\n        self.label = \"Multiscale Curvatures\"\n        self.description = \"This tool calculates several multiscale curvatures and curvature-based indices from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        curv_type = arcpy.Parameter(\n            displayName=\"Curvature Type\",\n            name=\"curv_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        curv_type.filter.type = \"ValueList\"\n        curv_type.filter.list = ['AccumulationCurv', 'Curvedness', 'DifferenceCurv', 'GaussianCurv', 'GeneratingFunction', 'HorizontalExcessCurv', 'MaximalCurv', 'MeanCurv', 'MinimalCurv', 'PlanCurv', 'ProfileCurv', 'RingCurv', 'Rotor', 'ShapeIndex', 'TangentialCurv', 'TotalCurv', 'Unsphericity', 'VerticalExcessCurv']\n        curv_type.value = 'ProfileCurv'\n\n        out_mag = arcpy.Parameter(\n            displayName=\"Output Magnitude File\",\n            name=\"out_mag\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_mag.filter.list = [\"tif\"]\n\n        out_scale = arcpy.Parameter(\n            displayName=\"Output Scale File\",\n            name=\"out_scale\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_scale.filter.list = [\"tif\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_scale.value = '0'\n\n        step = arcpy.Parameter(\n            displayName=\"Base Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step.value = '1'\n\n        num_steps = arcpy.Parameter(\n            displayName=\"Number of Steps\",\n            name=\"num_steps\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_steps.value = '1'\n\n        step_nonlinearity = arcpy.Parameter(\n            displayName=\"Step Nonlinearity\",\n            name=\"step_nonlinearity\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        step_nonlinearity.value = '1.0'\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'True'\n\n        standardize = arcpy.Parameter(\n            displayName=\"Standardize Each Scale?\",\n            name=\"standardize\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        standardize.value = 'False'\n\n        params = [dem, curv_type, out_mag, out_scale, min_scale, step, num_steps, step_nonlinearity, log, standardize]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        curv_type = parameters[1].valueAsText\n        out_mag = parameters[2].valueAsText\n        out_scale = parameters[3].valueAsText\n        min_scale = parameters[4].valueAsText\n        step = parameters[5].valueAsText\n        num_steps = parameters[6].valueAsText\n        step_nonlinearity = parameters[7].valueAsText\n        log = parameters[8].valueAsText\n        standardize = parameters[9].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multiscale_curvatures(dem=dem, curv_type=curv_type, out_mag=out_mag, out_scale=out_scale, min_scale=min_scale, step=step, num_steps=num_steps, step_nonlinearity=step_nonlinearity, log=log, standardize=standardize)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultiscaleElevationPercentile(object):\n    def __init__(self):\n        self.label = \"Multiscale Elevation Percentile\"\n        self.description = \"Calculates surface roughness over a range of spatial scales.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_mag = arcpy.Parameter(\n            displayName=\"Output Roughness Magnitude File\",\n            name=\"out_mag\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_mag.filter.list = [\"tif\"]\n\n        out_scale = arcpy.Parameter(\n            displayName=\"Output Roughness Scale File\",\n            name=\"out_scale\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_scale.filter.list = [\"tif\"]\n\n        sig_digits = arcpy.Parameter(\n            displayName=\"Number of Significant Digits\",\n            name=\"sig_digits\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sig_digits.value = '3'\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_scale.value = '4'\n\n        step = arcpy.Parameter(\n            displayName=\"Base Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step.value = '1'\n\n        num_steps = arcpy.Parameter(\n            displayName=\"Number of Steps\",\n            name=\"num_steps\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_steps.value = '10'\n\n        step_nonlinearity = arcpy.Parameter(\n            displayName=\"Step Nonlinearity\",\n            name=\"step_nonlinearity\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step_nonlinearity.value = '1.0'\n\n        params = [dem, out_mag, out_scale, sig_digits, min_scale, step, num_steps, step_nonlinearity]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        out_mag = parameters[1].valueAsText\n        out_scale = parameters[2].valueAsText\n        sig_digits = parameters[3].valueAsText\n        min_scale = parameters[4].valueAsText\n        step = parameters[5].valueAsText\n        num_steps = parameters[6].valueAsText\n        step_nonlinearity = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multiscale_elevation_percentile(dem=dem, out_mag=out_mag, out_scale=out_scale, sig_digits=sig_digits, min_scale=min_scale, step=step, num_steps=num_steps, step_nonlinearity=step_nonlinearity)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultiscaleRoughness(object):\n    def __init__(self):\n        self.label = \"Multiscale Roughness\"\n        self.description = \"Calculates surface roughness over a range of spatial scales.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_mag = arcpy.Parameter(\n            displayName=\"Output Roughness Magnitude File\",\n            name=\"out_mag\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_mag.filter.list = [\"tif\"]\n\n        out_scale = arcpy.Parameter(\n            displayName=\"Output Roughness Scale File\",\n            name=\"out_scale\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_scale.filter.list = [\"tif\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_scale.value = '1'\n\n        max_scale = arcpy.Parameter(\n            displayName=\"Maximum Search Neighbourhood Radius (grid cells)\",\n            name=\"max_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        step = arcpy.Parameter(\n            displayName=\"Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step.value = '1'\n\n        params = [dem, out_mag, out_scale, min_scale, max_scale, step]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        out_mag = parameters[1].valueAsText\n        out_scale = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        max_scale = parameters[4].valueAsText\n        step = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multiscale_roughness(dem=dem, out_mag=out_mag, out_scale=out_scale, min_scale=min_scale, max_scale=max_scale, step=step)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultiscaleRoughnessSignature(object):\n    def __init__(self):\n        self.label = \"Multiscale Roughness Signature\"\n        self.description = \"Calculates the surface roughness for points over a range of spatial scales.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        points = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"points\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        points.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_scale.value = '1'\n\n        max_scale = arcpy.Parameter(\n            displayName=\"Maximum Search Neighbourhood Radius (grid cells)\",\n            name=\"max_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        step = arcpy.Parameter(\n            displayName=\"Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step.value = '1'\n\n        params = [dem, points, output, min_scale, max_scale, step]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        points = parameters[1].valueAsText\n        if points is not None:\n            desc = arcpy.Describe(points)\n            points = desc.catalogPath\n        output = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        max_scale = parameters[4].valueAsText\n        step = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multiscale_roughness_signature(dem=dem, points=points, output=output, min_scale=min_scale, max_scale=max_scale, step=step)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultiscaleStdDevNormals(object):\n    def __init__(self):\n        self.label = \"Multiscale Std Dev Normals\"\n        self.description = \"Calculates surface roughness over a range of spatial scales.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_mag = arcpy.Parameter(\n            displayName=\"Output Roughness Magnitude File\",\n            name=\"out_mag\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_mag.filter.list = [\"tif\"]\n\n        out_scale = arcpy.Parameter(\n            displayName=\"Output Roughness Scale File\",\n            name=\"out_scale\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_scale.filter.list = [\"tif\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_scale.value = '1'\n\n        step = arcpy.Parameter(\n            displayName=\"Base Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step.value = '1'\n\n        num_steps = arcpy.Parameter(\n            displayName=\"Number of Steps\",\n            name=\"num_steps\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_steps.value = '10'\n\n        step_nonlinearity = arcpy.Parameter(\n            displayName=\"Step Nonlinearity\",\n            name=\"step_nonlinearity\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        step_nonlinearity.value = '1.0'\n\n        params = [dem, out_mag, out_scale, min_scale, step, num_steps, step_nonlinearity]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        out_mag = parameters[1].valueAsText\n        out_scale = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        step = parameters[4].valueAsText\n        num_steps = parameters[5].valueAsText\n        step_nonlinearity = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multiscale_std_dev_normals(dem=dem, out_mag=out_mag, out_scale=out_scale, min_scale=min_scale, step=step, num_steps=num_steps, step_nonlinearity=step_nonlinearity)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultiscaleStdDevNormalsSignature(object):\n    def __init__(self):\n        self.label = \"Multiscale Std Dev Normals Signature\"\n        self.description = \"Calculates the surface roughness for points over a range of spatial scales.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        points = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"points\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        points.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_scale.value = '1'\n\n        step = arcpy.Parameter(\n            displayName=\"Base Step Size\",\n            name=\"step\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step.value = '1'\n\n        num_steps = arcpy.Parameter(\n            displayName=\"Number of Steps\",\n            name=\"num_steps\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_steps.value = '10'\n\n        step_nonlinearity = arcpy.Parameter(\n            displayName=\"Step Nonlinearity\",\n            name=\"step_nonlinearity\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        step_nonlinearity.value = '1.0'\n\n        params = [dem, points, output, min_scale, step, num_steps, step_nonlinearity]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        points = parameters[1].valueAsText\n        if points is not None:\n            desc = arcpy.Describe(points)\n            points = desc.catalogPath\n        output = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        step = parameters[4].valueAsText\n        num_steps = parameters[5].valueAsText\n        step_nonlinearity = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multiscale_std_dev_normals_signature(dem=dem, points=points, output=output, min_scale=min_scale, step=step, num_steps=num_steps, step_nonlinearity=step_nonlinearity)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass MultiscaleTopographicPositionImage(object):\n    def __init__(self):\n        self.label = \"Multiscale Topographic Position Image\"\n        self.description = \"Creates a multiscale topographic position image from three DEVmax rasters of differing spatial scale ranges.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        local = arcpy.Parameter(\n            displayName=\"Input Local-Scale File\",\n            name=\"local\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        meso = arcpy.Parameter(\n            displayName=\"Input Meso-Scale File\",\n            name=\"meso\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        broad = arcpy.Parameter(\n            displayName=\"Input Broad-Scale File\",\n            name=\"broad\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        hillshade = arcpy.Parameter(\n            displayName=\"Optional Hillshade File\",\n            name=\"hillshade\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        lightness = arcpy.Parameter(\n            displayName=\"Image Lightness Value\",\n            name=\"lightness\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        lightness.value = '1.2'\n\n        params = [local, meso, broad, hillshade, output, lightness]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        local = parameters[0].valueAsText\n        if local is not None:\n            desc = arcpy.Describe(local)\n            local = desc.catalogPath\n        meso = parameters[1].valueAsText\n        if meso is not None:\n            desc = arcpy.Describe(meso)\n            meso = desc.catalogPath\n        broad = parameters[2].valueAsText\n        if broad is not None:\n            desc = arcpy.Describe(broad)\n            broad = desc.catalogPath\n        hillshade = parameters[3].valueAsText\n        if hillshade is not None:\n            desc = arcpy.Describe(hillshade)\n            hillshade = desc.catalogPath\n        output = parameters[4].valueAsText\n        lightness = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.multiscale_topographic_position_image(local=local, meso=meso, broad=broad, hillshade=hillshade, output=output, lightness=lightness)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NarrownessIndex(object):\n    def __init__(self):\n        self.label = \"Narrowness Index\"\n        self.description = \"Calculates the narrowness of raster polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.narrowness_index(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NaturalNeighbourInterpolation(object):\n    def __init__(self):\n        self.label = \"Natural Neighbour Interpolation\"\n        self.description = \"Creates a raster grid based on Sibson's natural neighbour method.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        use_z = arcpy.Parameter(\n            displayName=\"Use Shapefile 'z' values?\",\n            name=\"use_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_z.value = 'False'\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip to convex hull?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = 'True'\n\n        params = [i, field, use_z, output, cell_size, base, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        use_z = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        cell_size = parameters[4].valueAsText\n        base = parameters[5].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        clip = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.natural_neighbour_interpolation(i=i, field=field, use_z=use_z, output=output, cell_size=cell_size, base=base, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NearestNeighbourGridding(object):\n    def __init__(self):\n        self.label = \"Nearest Neighbour Gridding\"\n        self.description = \"Creates a raster grid based on a set of vector points and assigns grid values using the nearest neighbour.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        use_z = arcpy.Parameter(\n            displayName=\"Use z-coordinate instead of field?\",\n            name=\"use_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_z.value = 'False'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_dist = arcpy.Parameter(\n            displayName=\"Maximum Search Distance\",\n            name=\"max_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, use_z, output, cell_size, base, max_dist]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        use_z = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        cell_size = parameters[4].valueAsText\n        base = parameters[5].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        max_dist = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.nearest_neighbour_gridding(i=i, field=field, use_z=use_z, output=output, cell_size=cell_size, base=base, max_dist=max_dist)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Negate(object):\n    def __init__(self):\n        self.label = \"Negate\"\n        self.description = \"Changes the sign of values in a raster or the 0-1 values of a Boolean raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.negate(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NewRasterFromBase(object):\n    def __init__(self):\n        self.label = \"New Raster From Base\"\n        self.description = \"Creates a new raster using a base image.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        base = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"base\",\n            datatype=[\"DERasterDataset\", \"DEShapefile\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        value = arcpy.Parameter(\n            displayName=\"Constant Value\",\n            name=\"value\",\n            datatype=[\"GPString\", \"GPDouble\"],\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        value.value = 'nodata'\n\n        data_type = arcpy.Parameter(\n            displayName=\"Data Type\",\n            name=\"data_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        data_type.filter.type = \"ValueList\"\n        data_type.filter.list = ['double', 'float', 'integer']\n        data_type.value = 'float'\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [base, output, value, data_type, cell_size]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        base = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        value = parameters[2].valueAsText\n        data_type = parameters[3].valueAsText\n        cell_size = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.new_raster_from_base(base=base, output=output, value=value, data_type=data_type, cell_size=cell_size)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NormalVectors(object):\n    def __init__(self):\n        self.label = \"Normal Vectors\"\n        self.description = \"Calculates normal vectors for points within a LAS file and stores these data (XYZ vector components) in the RGB field.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        radius.value = '1.0'\n\n        params = [i, output, radius]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        radius = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.normal_vectors(i=i, output=output, radius=radius)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NormalizeLidar(object):\n    def __init__(self):\n        self.label = \"Normalize Lidar\"\n        self.description = \"Normalizes a LiDAR point cloud.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR File\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Lidar File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        dtm = arcpy.Parameter(\n            displayName=\"Input DTM Raster File\",\n            name=\"dtm\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, output, dtm]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        dtm = parameters[2].valueAsText\n        if dtm is not None:\n            desc = arcpy.Describe(dtm)\n            dtm = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.normalize_lidar(i=i, output=output, dtm=dtm)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NormalizedDifferenceIndex(object):\n    def __init__(self):\n        self.label = \"Normalized Difference Index\"\n        self.description = \"Calculate a normalized-difference index (NDI) from two bands of multispectral image data.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input 1 File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input 2 File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        clip = arcpy.Parameter(\n            displayName=\"Distribution Tail Clip Amount (%)\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '0.0'\n\n        correction = arcpy.Parameter(\n            displayName=\"Correction value\",\n            name=\"correction\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        correction.value = '0.0'\n\n        params = [input1, input2, output, clip, correction]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        clip = parameters[3].valueAsText\n        correction = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.normalized_difference_index(input1=input1, input2=input2, output=output, clip=clip, correction=correction)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Not(object):\n    def __init__(self):\n        self.label = \"Not\"\n        self.description = \"Performs a logical NOT operator on two Boolean raster images.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.Not(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NotEqualTo(object):\n    def __init__(self):\n        self.label = \"Not Equal To\"\n        self.description = \"Performs a not-equal-to comparison operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.not_equal_to(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NumDownslopeNeighbours(object):\n    def __init__(self):\n        self.label = \"Num Downslope Neighbours\"\n        self.description = \"Calculates the number of downslope neighbours to each grid cell in a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.num_downslope_neighbours(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NumInflowingNeighbours(object):\n    def __init__(self):\n        self.label = \"Num Inflowing Neighbours\"\n        self.description = \"Computes the number of inflowing neighbours to each cell in an input DEM based on the D8 algorithm.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.num_inflowing_neighbours(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass NumUpslopeNeighbours(object):\n    def __init__(self):\n        self.label = \"Num Upslope Neighbours\"\n        self.description = \"Calculates the number of upslope neighbours to each grid cell in a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.num_upslope_neighbours(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass OlympicFilter(object):\n    def __init__(self):\n        self.label = \"Olympic Filter\"\n        self.description = \"Performs an olympic smoothing filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.olympic_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Opening(object):\n    def __init__(self):\n        self.label = \"Opening\"\n        self.description = \"An opening is a mathematical morphology operation involving a dilation (max filter) of an erosion (min filter) set.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.opening(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Openness(object):\n    def __init__(self):\n        self.label = \"Openness\"\n        self.description = \"This tool calculates the topographic openness index from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        pos_output = arcpy.Parameter(\n            displayName=\"Positive Openness Output Raster\",\n            name=\"pos_output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        pos_output.filter.list = [\"tif\"]\n\n        neg_output = arcpy.Parameter(\n            displayName=\"Negative Openness Output Raster\",\n            name=\"neg_output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        neg_output.filter.list = [\"tif\"]\n\n        dist = arcpy.Parameter(\n            displayName=\"Search Distance (grid cells)\",\n            name=\"dist\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        dist.value = '20'\n\n        params = [i, pos_output, neg_output, dist]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        pos_output = parameters[1].valueAsText\n        neg_output = parameters[2].valueAsText\n        dist = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.openness(i=i, pos_output=pos_output, neg_output=neg_output, dist=dist)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Or(object):\n    def __init__(self):\n        self.label = \"Or\"\n        self.description = \"Performs a logical OR operator on two Boolean raster images.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.Or(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PairedSampleTTest(object):\n    def __init__(self):\n        self.label = \"Paired Sample T Test\"\n        self.description = \"Performs a 2-sample K-S test for significant differences on two input rasters.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"First Input File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Second Input File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        num_samples = arcpy.Parameter(\n            displayName=\"Num. Samples (blank for whole image)\",\n            name=\"num_samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [input1, input2, output, num_samples]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        num_samples = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.paired_sample_t_test(input1=input1, input2=input2, output=output, num_samples=num_samples)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PanchromaticSharpening(object):\n    def __init__(self):\n        self.label = \"Panchromatic Sharpening\"\n        self.description = \"Increases the spatial resolution of image data by combining multispectral bands with panchromatic data.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        red = arcpy.Parameter(\n            displayName=\"Input Red Band File (optional; only if colour-composite not specified)\",\n            name=\"red\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        green = arcpy.Parameter(\n            displayName=\"Input Green Band File (optional; only if colour-composite not specified)\",\n            name=\"green\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        blue = arcpy.Parameter(\n            displayName=\"Input Blue Band File (optional; only if colour-composite not specified)\",\n            name=\"blue\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        composite = arcpy.Parameter(\n            displayName=\"Input Colour-Composite Image File (optional; only if individual bands not specified)\",\n            name=\"composite\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        pan = arcpy.Parameter(\n            displayName=\"Input Panchromatic Band File\",\n            name=\"pan\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Colour Composite File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        method = arcpy.Parameter(\n            displayName=\"Pan-Sharpening Method\",\n            name=\"method\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        method.filter.type = \"ValueList\"\n        method.filter.list = ['brovey', 'ihs']\n        method.value = 'brovey'\n\n        params = [red, green, blue, composite, pan, output, method]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        red = parameters[0].valueAsText\n        if red is not None:\n            desc = arcpy.Describe(red)\n            red = desc.catalogPath\n        green = parameters[1].valueAsText\n        if green is not None:\n            desc = arcpy.Describe(green)\n            green = desc.catalogPath\n        blue = parameters[2].valueAsText\n        if blue is not None:\n            desc = arcpy.Describe(blue)\n            blue = desc.catalogPath\n        composite = parameters[3].valueAsText\n        if composite is not None:\n            desc = arcpy.Describe(composite)\n            composite = desc.catalogPath\n        pan = parameters[4].valueAsText\n        if pan is not None:\n            desc = arcpy.Describe(pan)\n            pan = desc.catalogPath\n        output = parameters[5].valueAsText\n        method = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.panchromatic_sharpening(red=red, green=green, blue=blue, composite=composite, pan=pan, output=output, method=method)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ParallelepipedClassification(object):\n    def __init__(self):\n        self.label = \"Parallelepiped Classification\"\n        self.description = \"Performs a supervised parallelepiped classification using training site polygons and multi-spectral images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Band Images\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        polys = arcpy.Parameter(\n            displayName=\"Input Training Polygons\",\n            name=\"polys\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        polys.filter.list = [\"Polygon\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Class Name Field\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [polys.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, polys, field, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        polys = parameters[1].valueAsText\n        if polys is not None:\n            desc = arcpy.Describe(polys)\n            polys = desc.catalogPath\n        field = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.parallelepiped_classification(inputs=inputs, polys=polys, field=field, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PatchOrientation(object):\n    def __init__(self):\n        self.label = \"Patch Orientation\"\n        self.description = \"Calculates the orientation of vector polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.patch_orientation(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PennockLandformClass(object):\n    def __init__(self):\n        self.label = \"Pennock Landform Class\"\n        self.description = \"Classifies hillslope zones based on slope, profile curvature, and plan curvature.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        slope = arcpy.Parameter(\n            displayName=\"Slope Threshold (degrees)\",\n            name=\"slope\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        slope.value = '3.0'\n\n        prof = arcpy.Parameter(\n            displayName=\"Profile Curvature Threshold\",\n            name=\"prof\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        prof.value = '0.1'\n\n        plan = arcpy.Parameter(\n            displayName=\"Plan Curvature Threshold\",\n            name=\"plan\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        plan.value = '0.0'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, slope, prof, plan, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        slope = parameters[2].valueAsText\n        prof = parameters[3].valueAsText\n        plan = parameters[4].valueAsText\n        zfactor = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.pennock_landform_class(dem=dem, output=output, slope=slope, prof=prof, plan=plan, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PercentElevRange(object):\n    def __init__(self):\n        self.label = \"Percent Elev Range\"\n        self.description = \"Calculates percent of elevation range from a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '3'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '3'\n\n        params = [dem, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.percent_elev_range(dem=dem, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PercentEqualTo(object):\n    def __init__(self):\n        self.label = \"Percent Equal To\"\n        self.description = \"Calculates the percentage of a raster stack that have cell values equal to an input on a cell-by-cell basis.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        comparison = arcpy.Parameter(\n            displayName=\"Input Comparison File\",\n            name=\"comparison\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, comparison, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        comparison = parameters[1].valueAsText\n        if comparison is not None:\n            desc = arcpy.Describe(comparison)\n            comparison = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.percent_equal_to(inputs=inputs, comparison=comparison, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PercentGreaterThan(object):\n    def __init__(self):\n        self.label = \"Percent Greater Than\"\n        self.description = \"Calculates the percentage of a raster stack that have cell values greater than an input on a cell-by-cell basis.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        comparison = arcpy.Parameter(\n            displayName=\"Input Comparison File\",\n            name=\"comparison\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, comparison, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        comparison = parameters[1].valueAsText\n        if comparison is not None:\n            desc = arcpy.Describe(comparison)\n            comparison = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.percent_greater_than(inputs=inputs, comparison=comparison, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PercentLessThan(object):\n    def __init__(self):\n        self.label = \"Percent Less Than\"\n        self.description = \"Calculates the percentage of a raster stack that have cell values less than an input on a cell-by-cell basis.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        comparison = arcpy.Parameter(\n            displayName=\"Input Comparison File\",\n            name=\"comparison\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, comparison, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        comparison = parameters[1].valueAsText\n        if comparison is not None:\n            desc = arcpy.Describe(comparison)\n            comparison = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.percent_less_than(inputs=inputs, comparison=comparison, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PercentageContrastStretch(object):\n    def __init__(self):\n        self.label = \"Percentage Contrast Stretch\"\n        self.description = \"Performs a percentage linear contrast stretch on input images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        clip = arcpy.Parameter(\n            displayName=\"Distribution Tail Clip Amount (%)\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '1.0'\n\n        tail = arcpy.Parameter(\n            displayName=\"Tail\",\n            name=\"tail\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        tail.filter.type = \"ValueList\"\n        tail.filter.list = ['upper', 'lower', 'both']\n        tail.value = 'both'\n\n        num_tones = arcpy.Parameter(\n            displayName=\"Number of Tones\",\n            name=\"num_tones\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_tones.value = '256'\n\n        params = [i, output, clip, tail, num_tones]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        clip = parameters[2].valueAsText\n        tail = parameters[3].valueAsText\n        num_tones = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.percentage_contrast_stretch(i=i, output=output, clip=clip, tail=tail, num_tones=num_tones)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PercentileFilter(object):\n    def __init__(self):\n        self.label = \"Percentile Filter\"\n        self.description = \"Performs a percentile filter on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        sig_digits = arcpy.Parameter(\n            displayName=\"Number of Significant Digits\",\n            name=\"sig_digits\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sig_digits.value = '2'\n\n        params = [i, output, filterx, filtery, sig_digits]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        sig_digits = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.percentile_filter(i=i, output=output, filterx=filterx, filtery=filtery, sig_digits=sig_digits)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PerimeterAreaRatio(object):\n    def __init__(self):\n        self.label = \"Perimeter Area Ratio\"\n        self.description = \"Calculates the perimeter-area ratio of vector polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.perimeter_area_ratio(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PhiCoefficient(object):\n    def __init__(self):\n        self.label = \"Phi Coefficient\"\n        self.description = \"This tool performs a binary classification accuracy assessment.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input Raster Image 1\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input Raster Image 2\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.phi_coefficient(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PickFromList(object):\n    def __init__(self):\n        self.label = \"Pick From List\"\n        self.description = \"Outputs the value from a raster stack specified by a position raster.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        pos_input = arcpy.Parameter(\n            displayName=\"Input Position File\",\n            name=\"pos_input\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, pos_input, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        pos_input = parameters[1].valueAsText\n        if pos_input is not None:\n            desc = arcpy.Describe(pos_input)\n            pos_input = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.pick_from_list(inputs=inputs, pos_input=pos_input, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PiecewiseContrastStretch(object):\n    def __init__(self):\n        self.label = \"Piecewise Contrast Stretch\"\n        self.description = \"Performs a piecewise contrast stretch on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster Image\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        function = arcpy.Parameter(\n            displayName=\"Piecewise Function Break-points:\",\n            name=\"function\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        greytones = arcpy.Parameter(\n            displayName=\"Number of Output Greytones:\",\n            name=\"greytones\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        greytones.value = '1024'\n\n        params = [i, output, function, greytones]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        function = parameters[2].valueAsText\n        greytones = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.piecewise_contrast_stretch(i=i, output=output, function=function, greytones=greytones)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PlanCurvature(object):\n    def __init__(self):\n        self.label = \"Plan Curvature\"\n        self.description = \"Calculates a plan (contour) curvature raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.plan_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PolygonArea(object):\n    def __init__(self):\n        self.label = \"Polygon Area\"\n        self.description = \"Calculates the area of vector polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.polygon_area(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PolygonLongAxis(object):\n    def __init__(self):\n        self.label = \"Polygon Long Axis\"\n        self.description = \"Used to map the long axis of polygon features.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.polygon_long_axis(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PolygonPerimeter(object):\n    def __init__(self):\n        self.label = \"Polygon Perimeter\"\n        self.description = \"Calculates the perimeter of vector polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.polygon_perimeter(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PolygonShortAxis(object):\n    def __init__(self):\n        self.label = \"Polygon Short Axis\"\n        self.description = \"Used to map the short axis of polygon features.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.polygon_short_axis(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Polygonize(object):\n    def __init__(self):\n        self.label = \"Polygonize\"\n        self.description = \"Creates a polygon layer from two or more intersecting line features contained in one or more input vector line files.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Vector Lines File\",\n            name=\"inputs\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n        inputs.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.polygonize(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PolygonsToLines(object):\n    def __init__(self):\n        self.label = \"Polygons To Lines\"\n        self.description = \"Converts vector polygons to polylines.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Line File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.polygons_to_lines(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Power(object):\n    def __init__(self):\n        self.label = \"Power\"\n        self.description = \"Raises the values in grid cells of one rasters, or a constant value, by values in another raster or constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.power(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PrewittFilter(object):\n    def __init__(self):\n        self.label = \"Prewitt Filter\"\n        self.description = \"Performs a Prewitt edge-detection filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        clip = arcpy.Parameter(\n            displayName=\"Distribution Tail Clip Amount (Percent)\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '0.0'\n\n        params = [i, output, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        clip = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.prewitt_filter(i=i, output=output, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PrincipalComponentAnalysis(object):\n    def __init__(self):\n        self.label = \"Principal Component Analysis\"\n        self.description = \"Performs a principal component analysis (PCA) on a multi-spectral dataset.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML Report File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        num_comp = arcpy.Parameter(\n            displayName=\"Num. of Component Images (blank for all)\",\n            name=\"num_comp\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        standardized = arcpy.Parameter(\n            displayName=\"Perform Standaradized PCA?\",\n            name=\"standardized\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [inputs, output, num_comp, standardized]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        num_comp = parameters[2].valueAsText\n        standardized = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.principal_component_analysis(inputs=inputs, output=output, num_comp=num_comp, standardized=standardized)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass PrintGeoTiffTags(object):\n    def __init__(self):\n        self.label = \"Print Geo Tiff Tags\"\n        self.description = \"Prints the tags within a GeoTIFF.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input GeoTIFF Raster File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.print_geo_tiff_tags(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Profile(object):\n    def __init__(self):\n        self.label = \"Profile\"\n        self.description = \"Plots profiles from digital surface models.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        lines = arcpy.Parameter(\n            displayName=\"Input Vector Line File\",\n            name=\"lines\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        lines.filter.list = [\"Polyline\"]\n\n        surface = arcpy.Parameter(\n            displayName=\"Input Surface File\",\n            name=\"surface\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [lines, surface, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        lines = parameters[0].valueAsText\n        if lines is not None:\n            desc = arcpy.Describe(lines)\n            lines = desc.catalogPath\n        surface = parameters[1].valueAsText\n        if surface is not None:\n            desc = arcpy.Describe(surface)\n            surface = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.profile(lines=lines, surface=surface, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ProfileCurvature(object):\n    def __init__(self):\n        self.label = \"Profile Curvature\"\n        self.description = \"Calculates a profile curvature raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.profile_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass QinFlowAccumulation(object):\n    def __init__(self):\n        self.label = \"Qin Flow Accumulation\"\n        self.description = \"Calculates Qin et al. (2007) flow accumulation.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['cells', 'specific contributing area', 'catchment area']\n        out_type.value = 'specific contributing area'\n\n        exponent = arcpy.Parameter(\n            displayName=\"Upper-bound Exponent Parameter\",\n            name=\"exponent\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        exponent.value = '10.0'\n\n        max_slope = arcpy.Parameter(\n            displayName=\"Upper-bound Slope Parameter (in degrees)\",\n            name=\"max_slope\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_slope.value = '45.0'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Convergence Threshold (grid cells; blank for none)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip the upper tail by 1%?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = 'False'\n\n        params = [dem, output, out_type, exponent, max_slope, threshold, log, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_type = parameters[2].valueAsText\n        exponent = parameters[3].valueAsText\n        max_slope = parameters[4].valueAsText\n        threshold = parameters[5].valueAsText\n        log = parameters[6].valueAsText\n        clip = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.qin_flow_accumulation(dem=dem, output=output, out_type=out_type, exponent=exponent, max_slope=max_slope, threshold=threshold, log=log, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Quantiles(object):\n    def __init__(self):\n        self.label = \"Quantiles\"\n        self.description = \"Transforms raster values into quantiles.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        num_quantiles = arcpy.Parameter(\n            displayName=\"Number of Quantiles\",\n            name=\"num_quantiles\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_quantiles.value = '5'\n\n        params = [i, output, num_quantiles]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        num_quantiles = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.quantiles(i=i, output=output, num_quantiles=num_quantiles)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass QuinnFlowAccumulation(object):\n    def __init__(self):\n        self.label = \"Quinn Flow Accumulation\"\n        self.description = \"Calculates Quinn et al. (1995) flow accumulation.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['cells', 'specific contributing area', 'catchment area']\n        out_type.value = 'specific contributing area'\n\n        exponent = arcpy.Parameter(\n            displayName=\"Exponent Parameter\",\n            name=\"exponent\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        exponent.value = '1.0'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Convergence Threshold (grid cells; blank for none)\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip the upper tail by 1%?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = 'False'\n\n        params = [dem, output, out_type, exponent, threshold, log, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_type = parameters[2].valueAsText\n        exponent = parameters[3].valueAsText\n        threshold = parameters[4].valueAsText\n        log = parameters[5].valueAsText\n        clip = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.quinn_flow_accumulation(dem=dem, output=output, out_type=out_type, exponent=exponent, threshold=threshold, log=log, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RadialBasisFunctionInterpolation(object):\n    def __init__(self):\n        self.label = \"Radial Basis Function Interpolation\"\n        self.description = \"Interpolates vector points into a raster surface using a radial basis function scheme.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        use_z = arcpy.Parameter(\n            displayName=\"Use z-coordinate instead of field?\",\n            name=\"use_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_z.value = 'False'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius (map units)\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        min_points = arcpy.Parameter(\n            displayName=\"Min. Number of Points\",\n            name=\"min_points\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        func_type = arcpy.Parameter(\n            displayName=\"Radial Basis Function Type\",\n            name=\"func_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        func_type.filter.type = \"ValueList\"\n        func_type.filter.list = ['ThinPlateSpline', 'PolyHarmonic', 'Gaussian', 'MultiQuadric', 'InverseMultiQuadric']\n        func_type.value = 'ThinPlateSpline'\n\n        poly_order = arcpy.Parameter(\n            displayName=\"Polynomial Order\",\n            name=\"poly_order\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        poly_order.filter.type = \"ValueList\"\n        poly_order.filter.list = ['none', 'constant', 'affine']\n        poly_order.value = 'none'\n\n        weight = arcpy.Parameter(\n            displayName=\"Weight\",\n            name=\"weight\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        weight.value = '0.1'\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, use_z, output, radius, min_points, func_type, poly_order, weight, cell_size, base]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        use_z = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        radius = parameters[4].valueAsText\n        min_points = parameters[5].valueAsText\n        func_type = parameters[6].valueAsText\n        poly_order = parameters[7].valueAsText\n        weight = parameters[8].valueAsText\n        cell_size = parameters[9].valueAsText\n        base = parameters[10].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.radial_basis_function_interpolation(i=i, field=field, use_z=use_z, output=output, radius=radius, min_points=min_points, func_type=func_type, poly_order=poly_order, weight=weight, cell_size=cell_size, base=base)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RadiusOfGyration(object):\n    def __init__(self):\n        self.label = \"Radius Of Gyration\"\n        self.description = \"Calculates the distance of cells from their polygon's centroid.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        text_output = arcpy.Parameter(\n            displayName=\"Output text?\",\n            name=\"text_output\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, output, text_output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        text_output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.radius_of_gyration(i=i, output=output, text_output=text_output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RaiseWalls(object):\n    def __init__(self):\n        self.label = \"Raise Walls\"\n        self.description = \"Raises walls in a DEM along a line or around a polygon, e.g. a watershed.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        input = arcpy.Parameter(\n            displayName=\"Input Vector Line or Polygon File\",\n            name=\"input\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        breach = arcpy.Parameter(\n            displayName=\"Input Breach Lines (optional)\",\n            name=\"breach\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        breach.filter.list = [\"Polyline\"]\n\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        height = arcpy.Parameter(\n            displayName=\"Wall Height\",\n            name=\"height\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        height.value = '100.0'\n\n        params = [input, breach, dem, output, height]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        breach = parameters[1].valueAsText\n        if breach is not None:\n            desc = arcpy.Describe(breach)\n            breach = desc.catalogPath\n        dem = parameters[2].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[3].valueAsText\n        height = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raise_walls(i=i, breach=breach, dem=dem, output=output, height=height)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RandomField(object):\n    def __init__(self):\n        self.label = \"Random Field\"\n        self.description = \"Creates an image containing random values.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        base = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [base, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        base = parameters[0].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.random_field(base=base, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RandomForestClassification(object):\n    def __init__(self):\n        self.label = \"Random Forest Classification\"\n        self.description = \"Performs a supervised random forest classification using training site polygons/points and predictor rasters.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Predictor Rasters\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        training = arcpy.Parameter(\n            displayName=\"Input Training Polygons/Points\",\n            name=\"training\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        field = arcpy.Parameter(\n            displayName=\"Class Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [training.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        split_criterion = arcpy.Parameter(\n            displayName=\"Split Criterion\",\n            name=\"split_criterion\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        split_criterion.filter.type = \"ValueList\"\n        split_criterion.filter.list = ['Gini', 'Entropy', 'ClassificationError']\n        split_criterion.value = 'Gini'\n\n        n_trees = arcpy.Parameter(\n            displayName=\"Number of Trees in Forest\",\n            name=\"n_trees\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        n_trees.value = '500'\n\n        min_samples_leaf = arcpy.Parameter(\n            displayName=\"Min Number of Samples to be a Leaf\",\n            name=\"min_samples_leaf\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_samples_leaf.value = '1'\n\n        min_samples_split = arcpy.Parameter(\n            displayName=\"Min Number of Samples Needed to Split Node\",\n            name=\"min_samples_split\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_samples_split.value = '2'\n\n        test_proportion = arcpy.Parameter(\n            displayName=\"Test Proportion\",\n            name=\"test_proportion\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        test_proportion.value = '0.2'\n\n        params = [inputs, training, field, output, split_criterion, n_trees, min_samples_leaf, min_samples_split, test_proportion]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        training = parameters[1].valueAsText\n        if training is not None:\n            desc = arcpy.Describe(training)\n            training = desc.catalogPath\n        field = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        split_criterion = parameters[4].valueAsText\n        n_trees = parameters[5].valueAsText\n        min_samples_leaf = parameters[6].valueAsText\n        min_samples_split = parameters[7].valueAsText\n        test_proportion = parameters[8].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.random_forest_classification(inputs=inputs, training=training, field=field, output=output, split_criterion=split_criterion, n_trees=n_trees, min_samples_leaf=min_samples_leaf, min_samples_split=min_samples_split, test_proportion=test_proportion)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RandomForestRegression(object):\n    def __init__(self):\n        self.label = \"Random Forest Regression\"\n        self.description = \"Performs a random forest regression analysis using training site data and predictor rasters.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Predictor Rasters\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        training = arcpy.Parameter(\n            displayName=\"Input Training Points\",\n            name=\"training\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        training.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Response Variable Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [training.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        n_trees = arcpy.Parameter(\n            displayName=\"Number of Trees in Forest\",\n            name=\"n_trees\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        n_trees.value = '100'\n\n        min_samples_leaf = arcpy.Parameter(\n            displayName=\"Min Number of Samples to be a Leaf\",\n            name=\"min_samples_leaf\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_samples_leaf.value = '1'\n\n        min_samples_split = arcpy.Parameter(\n            displayName=\"Min Number of Samples Needed to Split Node\",\n            name=\"min_samples_split\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_samples_split.value = '2'\n\n        test_proportion = arcpy.Parameter(\n            displayName=\"Test Proportion\",\n            name=\"test_proportion\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        test_proportion.value = '0.2'\n\n        params = [inputs, training, field, output, n_trees, min_samples_leaf, min_samples_split, test_proportion]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        training = parameters[1].valueAsText\n        if training is not None:\n            desc = arcpy.Describe(training)\n            training = desc.catalogPath\n        field = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        n_trees = parameters[4].valueAsText\n        min_samples_leaf = parameters[5].valueAsText\n        min_samples_split = parameters[6].valueAsText\n        test_proportion = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.random_forest_regression(inputs=inputs, training=training, field=field, output=output, n_trees=n_trees, min_samples_leaf=min_samples_leaf, min_samples_split=min_samples_split, test_proportion=test_proportion)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RandomSample(object):\n    def __init__(self):\n        self.label = \"Random Sample\"\n        self.description = \"Creates an image containing randomly located sample grid cells with unique IDs.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        base = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        num_samples = arcpy.Parameter(\n            displayName=\"Num. Samples\",\n            name=\"num_samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_samples.value = '1000'\n\n        params = [base, output, num_samples]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        base = parameters[0].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        output = parameters[1].valueAsText\n        num_samples = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.random_sample(base=base, output=output, num_samples=num_samples)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RangeFilter(object):\n    def __init__(self):\n        self.label = \"Range Filter\"\n        self.description = \"Assigns each cell in the output grid the range of values in a moving window centred on each grid cell in the input raster.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.range_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterArea(object):\n    def __init__(self):\n        self.label = \"Raster Area\"\n        self.description = \"Calculates the area of polygons or classes within a raster image.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_text = arcpy.Parameter(\n            displayName=\"Output text?\",\n            name=\"out_text\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        units = arcpy.Parameter(\n            displayName=\"Units\",\n            name=\"units\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        units.filter.type = \"ValueList\"\n        units.filter.list = ['grid cells', 'map units']\n        units.value = 'grid cells'\n\n        zero_back = arcpy.Parameter(\n            displayName=\"Treat zero values as background?\",\n            name=\"zero_back\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, output, out_text, units, zero_back]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_text = parameters[2].valueAsText\n        units = parameters[3].valueAsText\n        zero_back = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_area(i=i, output=output, out_text=out_text, units=units, zero_back=zero_back)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterCalculator(object):\n    def __init__(self):\n        self.label = \"Raster Calculator\"\n        self.description = \"Performs a complex mathematical operations on one or more input raster images on a cell-to-cell basis.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        statement = arcpy.Parameter(\n            displayName=\"Statement:\",\n            name=\"statement\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [statement, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        statement = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_calculator(statement=statement, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterCellAssignment(object):\n    def __init__(self):\n        self.label = \"Raster Cell Assignment\"\n        self.description = \"Assign row or column number to cells.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        assign = arcpy.Parameter(\n            displayName=\"Which spatial variable should be assigned?\",\n            name=\"assign\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        assign.filter.type = \"ValueList\"\n        assign.filter.list = ['column', 'row', 'x', 'y']\n        assign.value = 'column'\n\n        params = [i, output, assign]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        assign = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_cell_assignment(i=i, output=output, assign=assign)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterHistogram(object):\n    def __init__(self):\n        self.label = \"Raster Histogram\"\n        self.description = \"Creates a histogram from raster values.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_histogram(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterPerimeter(object):\n    def __init__(self):\n        self.label = \"Raster Perimeter\"\n        self.description = \"Calculates the perimeters of polygons or classes within a raster image.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_text = arcpy.Parameter(\n            displayName=\"Output text?\",\n            name=\"out_text\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        units = arcpy.Parameter(\n            displayName=\"Units\",\n            name=\"units\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        units.filter.type = \"ValueList\"\n        units.filter.list = ['grid cells', 'map units']\n        units.value = 'grid cells'\n\n        zero_back = arcpy.Parameter(\n            displayName=\"Treat zero values as background?\",\n            name=\"zero_back\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, output, out_text, units, zero_back]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_text = parameters[2].valueAsText\n        units = parameters[3].valueAsText\n        zero_back = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_perimeter(i=i, output=output, out_text=out_text, units=units, zero_back=zero_back)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterStreamsToVector(object):\n    def __init__(self):\n        self.label = \"Raster Streams To Vector\"\n        self.description = \"Converts a raster stream file into a vector file.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [streams, d8_pntr, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        streams = parameters[0].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        d8_pntr = parameters[1].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_streams_to_vector(streams=streams, d8_pntr=d8_pntr, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterSummaryStats(object):\n    def __init__(self):\n        self.label = \"Raster Summary Stats\"\n        self.description = \"Measures a rasters min, max, average, standard deviation, num. non-nodata cells, and total.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_summary_stats(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterToVectorLines(object):\n    def __init__(self):\n        self.label = \"Raster To Vector Lines\"\n        self.description = \"Converts a raster lines features into a vector of the POLYLINE shapetype\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster Lines File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_to_vector_lines(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterToVectorPoints(object):\n    def __init__(self):\n        self.label = \"Raster To Vector Points\"\n        self.description = \"Converts a raster dataset to a vector of the POINT shapetype.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Points File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_to_vector_points(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterToVectorPolygons(object):\n    def __init__(self):\n        self.label = \"Raster To Vector Polygons\"\n        self.description = \"Converts a raster dataset to a vector of the POLYGON shapetype.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygons File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.raster_to_vector_polygons(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RasterizeStreams(object):\n    def __init__(self):\n        self.label = \"Rasterize Streams\"\n        self.description = \"Rasterizes vector streams based on Lindsay (2016) method.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        streams = arcpy.Parameter(\n            displayName=\"Input Vector Streams File\",\n            name=\"streams\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        streams.filter.list = [\"Polyline\"]\n\n        base = arcpy.Parameter(\n            displayName=\"Input Base Raster File\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        nodata = arcpy.Parameter(\n            displayName=\"Use NoData value for background?\",\n            name=\"nodata\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        nodata.value = 'True'\n\n        feature_id = arcpy.Parameter(\n            displayName=\"Use feature number as output value?\",\n            name=\"feature_id\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        feature_id.value = 'False'\n\n        params = [streams, base, output, nodata, feature_id]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        streams = parameters[0].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        base = parameters[1].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        output = parameters[2].valueAsText\n        nodata = parameters[3].valueAsText\n        feature_id = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.rasterize_streams(streams=streams, base=base, output=output, nodata=nodata, feature_id=feature_id)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Reciprocal(object):\n    def __init__(self):\n        self.label = \"Reciprocal\"\n        self.description = \"Returns the reciprocal (i.e. 1 / z) of values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.reciprocal(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Reclass(object):\n    def __init__(self):\n        self.label = \"Reclass\"\n        self.description = \"Reclassifies the values in a raster image.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        reclass_vals = arcpy.Parameter(\n            displayName=\"Reclass Values (new value; from value; to less than)\",\n            name=\"reclass_vals\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        assign_mode = arcpy.Parameter(\n            displayName=\"Operate in assign mode? (i.e. Reclass data are pair values rather than triplets)\",\n            name=\"assign_mode\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, reclass_vals, assign_mode]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        reclass_vals = parameters[2].valueAsText\n        assign_mode = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.reclass(i=i, output=output, reclass_vals=reclass_vals, assign_mode=assign_mode)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ReclassEqualInterval(object):\n    def __init__(self):\n        self.label = \"Reclass Equal Interval\"\n        self.description = \"Reclassifies the values in a raster image based on equal-ranges.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        interval = arcpy.Parameter(\n            displayName=\"Class Interval Size\",\n            name=\"interval\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        interval.value = '10.0'\n\n        start_val = arcpy.Parameter(\n            displayName=\"Starting Value\",\n            name=\"start_val\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        end_val = arcpy.Parameter(\n            displayName=\"Ending Value\",\n            name=\"end_val\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, interval, start_val, end_val]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        interval = parameters[2].valueAsText\n        start_val = parameters[3].valueAsText\n        end_val = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.reclass_equal_interval(i=i, output=output, interval=interval, start_val=start_val, end_val=end_val)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ReclassFromFile(object):\n    def __init__(self):\n        self.label = \"Reclass From File\"\n        self.description = \"Reclassifies the values in a raster image using reclass ranges in a text file.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        reclass_file = arcpy.Parameter(\n            displayName=\"Input Reclass Text File\",\n            name=\"reclass_file\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, reclass_file, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        reclass_file = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.reclass_from_file(i=i, reclass_file=reclass_file, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ReconcileMultipleHeaders(object):\n    def __init__(self):\n        self.label = \"Reconcile Multiple Headers\"\n        self.description = \"This tool adjusts the crop yield values for data sets collected with multiple headers or combines.\"\n        self.category = \"Precision Agriculture\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Points\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        region_field = arcpy.Parameter(\n            displayName=\"Region Field Name\",\n            name=\"region_field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        region_field.parameterDependencies = [i.name]\n\n        yield_field = arcpy.Parameter(\n            displayName=\"Yield Field Name\",\n            name=\"yield_field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        yield_field.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Points\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius (m)\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        min_yield = arcpy.Parameter(\n            displayName=\"Minimum Yield\",\n            name=\"min_yield\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_yield = arcpy.Parameter(\n            displayName=\"Maximum Yield\",\n            name=\"max_yield\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        mean_tonnage = arcpy.Parameter(\n            displayName=\"Overall Average Tonnage (Optional)\",\n            name=\"mean_tonnage\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, region_field, yield_field, output, radius, min_yield, max_yield, mean_tonnage]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        region_field = parameters[1].valueAsText\n        yield_field = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        radius = parameters[4].valueAsText\n        min_yield = parameters[5].valueAsText\n        max_yield = parameters[6].valueAsText\n        mean_tonnage = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.reconcile_multiple_headers(i=i, region_field=region_field, yield_field=yield_field, output=output, radius=radius, min_yield=min_yield, max_yield=max_yield, mean_tonnage=mean_tonnage)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RecoverFlightlineInfo(object):\n    def __init__(self):\n        self.label = \"Recover Flightline Info\"\n        self.description = \"Associates LiDAR points by their flightlines.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR Points\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        max_time_diff = arcpy.Parameter(\n            displayName=\"Maximum In-Flightline Time Difference (seconds)\",\n            name=\"max_time_diff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_time_diff.value = '5.0'\n\n        pt_src_id = arcpy.Parameter(\n            displayName=\"Add flightline info to the Point Source ID?\",\n            name=\"pt_src_id\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        pt_src_id.value = 'False'\n\n        user_data = arcpy.Parameter(\n            displayName=\"Add flightline info to the User Data?\",\n            name=\"user_data\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        user_data.value = 'False'\n\n        rgb = arcpy.Parameter(\n            displayName=\"Add flightline info to the RGB colour data?\",\n            name=\"rgb\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        rgb.value = 'False'\n\n        params = [i, output, max_time_diff, pt_src_id, user_data, rgb]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        max_time_diff = parameters[2].valueAsText\n        pt_src_id = parameters[3].valueAsText\n        user_data = parameters[4].valueAsText\n        rgb = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.recover_flightline_info(i=i, output=output, max_time_diff=max_time_diff, pt_src_id=pt_src_id, user_data=user_data, rgb=rgb)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RecreatePassLines(object):\n    def __init__(self):\n        self.label = \"Recreate Pass Lines\"\n        self.description = \"This tool can be used to approximate the harvester pass lines from yield points.\"\n        self.category = \"Precision Agriculture\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Points\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        yield_field_name = arcpy.Parameter(\n            displayName=\"Yield Field Name\",\n            name=\"yield_field_name\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        yield_field_name.parameterDependencies = [i.name]\n\n        output_lines = arcpy.Parameter(\n            displayName=\"Output Pass Line\",\n            name=\"output_lines\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        output_points = arcpy.Parameter(\n            displayName=\"Output Points\",\n            name=\"output_points\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        max_change_in_heading = arcpy.Parameter(\n            displayName=\"Max Change In Heading (degrees)\",\n            name=\"max_change_in_heading\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_change_in_heading.value = '25.0'\n\n        ignore_zeros = arcpy.Parameter(\n            displayName=\"Ignore zero-valued yield points?\",\n            name=\"ignore_zeros\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        ignore_zeros.value = 'False'\n\n        params = [i, yield_field_name, output_lines, output_points, max_change_in_heading, ignore_zeros]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        yield_field_name = parameters[1].valueAsText\n        output_lines = parameters[2].valueAsText\n        output_points = parameters[3].valueAsText\n        max_change_in_heading = parameters[4].valueAsText\n        ignore_zeros = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.recreate_pass_lines(i=i, yield_field_name=yield_field_name, output_lines=output_lines, output_points=output_points, max_change_in_heading=max_change_in_heading, ignore_zeros=ignore_zeros)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ReinitializeAttributeTable(object):\n    def __init__(self):\n        self.label = \"Reinitialize Attribute Table\"\n        self.description = \"Reinitializes a vector's attribute table deleting all fields but the feature ID (FID).\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.reinitialize_attribute_table(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RelatedCircumscribingCircle(object):\n    def __init__(self):\n        self.label = \"Related Circumscribing Circle\"\n        self.description = \"Calculates the related circumscribing circle of vector polygons.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.related_circumscribing_circle(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RelativeAspect(object):\n    def __init__(self):\n        self.label = \"Relative Aspect\"\n        self.description = \"Calculates relative aspect (relative to a user-specified direction) from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        azimuth = arcpy.Parameter(\n            displayName=\"Azimuth\",\n            name=\"azimuth\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        azimuth.value = '0.0'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, azimuth, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        azimuth = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.relative_aspect(dem=dem, output=output, azimuth=azimuth, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RelativeTopographicPosition(object):\n    def __init__(self):\n        self.label = \"Relative Topographic Position\"\n        self.description = \"Calculates the relative topographic position index from a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [dem, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.relative_topographic_position(dem=dem, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RemoveFieldEdgePoints(object):\n    def __init__(self):\n        self.label = \"Remove Field Edge Points\"\n        self.description = \"This tool can be used to remove, or flag, most of the points along the edges from a crop yield data set.\"\n        self.category = \"Precision Agriculture\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Points\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Points\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        dist = arcpy.Parameter(\n            displayName=\"Average Distance Between Passes (m)\",\n            name=\"dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_change_in_heading = arcpy.Parameter(\n            displayName=\"Max Change In Heading (degrees)\",\n            name=\"max_change_in_heading\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_change_in_heading.value = '25.0'\n\n        flag_edges = arcpy.Parameter(\n            displayName=\"Don't remove edge points, just flag them?\",\n            name=\"flag_edges\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        flag_edges.value = 'False'\n\n        params = [i, output, dist, max_change_in_heading, flag_edges]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        dist = parameters[2].valueAsText\n        max_change_in_heading = parameters[3].valueAsText\n        flag_edges = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.remove_field_edge_points(i=i, output=output, dist=dist, max_change_in_heading=max_change_in_heading, flag_edges=flag_edges)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RemoveOffTerrainObjects(object):\n    def __init__(self):\n        self.label = \"Remove Off Terrain Objects\"\n        self.description = \"Removes off-terrain objects from a raster digital elevation model (DEM).\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Dimension\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        filter.value = '11'\n\n        slope = arcpy.Parameter(\n            displayName=\"Slope Threshold\",\n            name=\"slope\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        slope.value = '15.0'\n\n        params = [dem, output, filter, slope]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        slope = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.remove_off_terrain_objects(dem=dem, output=output, filter=filter, slope=slope)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RemovePolygonHoles(object):\n    def __init__(self):\n        self.label = \"Remove Polygon Holes\"\n        self.description = \"Removes holes within the features of a vector polygon file.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.remove_polygon_holes(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RemoveRasterPolygonHoles(object):\n    def __init__(self):\n        self.label = \"Remove Raster Polygon Holes\"\n        self.description = \"Removes polygon holes, or 'donut-holes', from raster polygons.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster Image\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        threshold = arcpy.Parameter(\n            displayName=\"Threshold Size (Grid Cells):\",\n            name=\"threshold\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        threshold.value = '3'\n\n        use_diagonals = arcpy.Parameter(\n            displayName=\"Use diagonal neighbours during clumping?\",\n            name=\"use_diagonals\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_diagonals.value = 'True'\n\n        params = [i, output, threshold, use_diagonals]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        threshold = parameters[2].valueAsText\n        use_diagonals = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.remove_raster_polygon_holes(i=i, output=output, threshold=threshold, use_diagonals=use_diagonals)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RemoveShortStreams(object):\n    def __init__(self):\n        self.label = \"Remove Short Streams\"\n        self.description = \"Removes short first-order streams from a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        min_length = arcpy.Parameter(\n            displayName=\"Minimum Tributary Length (map units)\",\n            name=\"min_length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, streams, output, min_length, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        min_length = parameters[3].valueAsText\n        esri_pntr = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.remove_short_streams(d8_pntr=d8_pntr, streams=streams, output=output, min_length=min_length, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RemoveSpurs(object):\n    def __init__(self):\n        self.label = \"Remove Spurs\"\n        self.description = \"Removes the spurs (pruning operation) from a Boolean line image; intended to be used on the output of the LineThinning tool.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        iterations = arcpy.Parameter(\n            displayName=\"Maximum Iterations\",\n            name=\"iterations\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        iterations.value = '10'\n\n        params = [i, output, iterations]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        iterations = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.remove_spurs(i=i, output=output, iterations=iterations)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RepairStreamVectorTopology(object):\n    def __init__(self):\n        self.label = \"Repair Stream Vector Topology\"\n        self.description = \"This tool resolves topological errors and inconsistencies associated with digitized vector streams.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Lines\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Lines\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        dist = arcpy.Parameter(\n            displayName=\"Snap Distance\",\n            name=\"dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        params = [i, output, dist]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        dist = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.repair_stream_vector_topology(i=i, output=output, dist=dist)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Resample(object):\n    def __init__(self):\n        self.label = \"Resample\"\n        self.description = \"Resamples one or more input images into a destination image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        method = arcpy.Parameter(\n            displayName=\"Resampling Method\",\n            name=\"method\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        method.filter.type = \"ValueList\"\n        method.filter.list = ['nn', 'bilinear', 'cc']\n        method.value = 'cc'\n\n        params = [inputs, output, cell_size, base, method]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        cell_size = parameters[2].valueAsText\n        base = parameters[3].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        method = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.resample(inputs=inputs, output=output, cell_size=cell_size, base=base, method=method)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RescaleValueRange(object):\n    def __init__(self):\n        self.label = \"Rescale Value Range\"\n        self.description = \"Performs a min-max contrast stretch on an input greytone image.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_min_val = arcpy.Parameter(\n            displayName=\"Output Raster Minimum Value\",\n            name=\"out_min_val\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        out_max_val = arcpy.Parameter(\n            displayName=\"Output Raster Maximum Value\",\n            name=\"out_max_val\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        clip_min = arcpy.Parameter(\n            displayName=\"Lower-Tail Clip Value (optional)\",\n            name=\"clip_min\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        clip_max = arcpy.Parameter(\n            displayName=\"Upper-Tail Clip Value (optional)\",\n            name=\"clip_max\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, out_min_val, out_max_val, clip_min, clip_max]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_min_val = parameters[2].valueAsText\n        out_max_val = parameters[3].valueAsText\n        clip_min = parameters[4].valueAsText\n        clip_max = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.rescale_value_range(i=i, output=output, out_min_val=out_min_val, out_max_val=out_max_val, clip_min=clip_min, clip_max=clip_max)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RgbToIhs(object):\n    def __init__(self):\n        self.label = \"Rgb To Ihs\"\n        self.description = \"Converts red, green, and blue (RGB) images into intensity, hue, and saturation (IHS) images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        red = arcpy.Parameter(\n            displayName=\"Input Red Band File (optional; only if colour-composite not specified)\",\n            name=\"red\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        green = arcpy.Parameter(\n            displayName=\"Input Green Band File (optional; only if colour-composite not specified)\",\n            name=\"green\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        blue = arcpy.Parameter(\n            displayName=\"Input Blue Band File (optional; only if colour-composite not specified)\",\n            name=\"blue\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        composite = arcpy.Parameter(\n            displayName=\"Input Colour-Composite Image File (optional; only if individual bands not specified)\",\n            name=\"composite\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        intensity = arcpy.Parameter(\n            displayName=\"Output Intensity File\",\n            name=\"intensity\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        intensity.filter.list = [\"tif\"]\n\n        hue = arcpy.Parameter(\n            displayName=\"Output Hue File\",\n            name=\"hue\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        hue.filter.list = [\"tif\"]\n\n        saturation = arcpy.Parameter(\n            displayName=\"Output Saturation File\",\n            name=\"saturation\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        saturation.filter.list = [\"tif\"]\n\n        params = [red, green, blue, composite, intensity, hue, saturation]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        red = parameters[0].valueAsText\n        if red is not None:\n            desc = arcpy.Describe(red)\n            red = desc.catalogPath\n        green = parameters[1].valueAsText\n        if green is not None:\n            desc = arcpy.Describe(green)\n            green = desc.catalogPath\n        blue = parameters[2].valueAsText\n        if blue is not None:\n            desc = arcpy.Describe(blue)\n            blue = desc.catalogPath\n        composite = parameters[3].valueAsText\n        if composite is not None:\n            desc = arcpy.Describe(composite)\n            composite = desc.catalogPath\n        intensity = parameters[4].valueAsText\n        hue = parameters[5].valueAsText\n        saturation = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.rgb_to_ihs(red=red, green=green, blue=blue, composite=composite, intensity=intensity, hue=hue, saturation=saturation)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Rho8FlowAccumulation(object):\n    def __init__(self):\n        self.label = \"Rho8 Flow Accumulation\"\n        self.description = \"Calculates Fairfield and Leymarie (1991) flow accumulation.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input DEM or Rho8 Pointer File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        out_type = arcpy.Parameter(\n            displayName=\"Output Type\",\n            name=\"out_type\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        out_type.filter.type = \"ValueList\"\n        out_type.filter.list = ['cells', 'specific contributing area', 'catchment area']\n        out_type.value = 'specific contributing area'\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip the upper tail by 1%?\",\n            name=\"clip\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = 'False'\n\n        pntr = arcpy.Parameter(\n            displayName=\"Is the input raster a Rho8 flow pointer?\",\n            name=\"pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        pntr.value = 'False'\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"If a pointer is input, does it use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [i, output, out_type, log, clip, pntr, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        out_type = parameters[2].valueAsText\n        log = parameters[3].valueAsText\n        clip = parameters[4].valueAsText\n        pntr = parameters[5].valueAsText\n        esri_pntr = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.rho8_flow_accumulation(i=i, output=output, out_type=out_type, log=log, clip=clip, pntr=pntr, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Rho8Pointer(object):\n    def __init__(self):\n        self.label = \"Rho8 Pointer\"\n        self.description = \"Calculates a stochastic Rho8 flow pointer raster from an input DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Should the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [dem, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        esri_pntr = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.rho8_pointer(dem=dem, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RingCurvature(object):\n    def __init__(self):\n        self.label = \"Ring Curvature\"\n        self.description = \"This tool calculates ring curvature from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.ring_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RiverCenterlines(object):\n    def __init__(self):\n        self.label = \"River Centerlines\"\n        self.description = \"Maps river centerlines from an input water raster.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster Image\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector Lines File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        min_length = arcpy.Parameter(\n            displayName=\"Min. Line Length (In Grid Cells)\",\n            name=\"min_length\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_length.value = '3'\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius (In Grid Cells)\",\n            name=\"radius\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        radius.value = '4'\n\n        params = [i, output, min_length, radius]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        min_length = parameters[2].valueAsText\n        radius = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.river_centerlines(i=i, output=output, min_length=min_length, radius=radius)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RobertsCrossFilter(object):\n    def __init__(self):\n        self.label = \"Roberts Cross Filter\"\n        self.description = \"Performs a Robert's cross edge-detection filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        clip = arcpy.Parameter(\n            displayName=\"Distribution Tail Clip Amount (Percent)\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '0.0'\n\n        params = [i, output, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        clip = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.roberts_cross_filter(i=i, output=output, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RootMeanSquareError(object):\n    def __init__(self):\n        self.label = \"Root Mean Square Error\"\n        self.description = \"Calculates the RMSE and other accuracy statistics.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, base]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        base = parameters[1].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.root_mean_square_error(i=i, base=base)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Rotor(object):\n    def __init__(self):\n        self.label = \"Rotor\"\n        self.description = \"This tool calculates rotor from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.rotor(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Round(object):\n    def __init__(self):\n        self.label = \"Round\"\n        self.description = \"Rounds the values in an input raster to the nearest integer value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.round(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass RuggednessIndex(object):\n    def __init__(self):\n        self.label = \"Ruggedness Index\"\n        self.description = \"Calculates the Riley et al.'s (1999) terrain ruggedness index from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.ruggedness_index(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ScharrFilter(object):\n    def __init__(self):\n        self.label = \"Scharr Filter\"\n        self.description = \"Performs a Scharr edge-detection filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        clip = arcpy.Parameter(\n            displayName=\"Distribution Tail Clip Amount (Percent)\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '0.0'\n\n        params = [i, output, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        clip = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.scharr_filter(i=i, output=output, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SedimentTransportIndex(object):\n    def __init__(self):\n        self.label = \"Sediment Transport Index\"\n        self.description = \"Calculates the sediment transport index.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        sca = arcpy.Parameter(\n            displayName=\"Input Specific Contributing Area (SCA) File\",\n            name=\"sca\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        slope = arcpy.Parameter(\n            displayName=\"Input Slope File\",\n            name=\"slope\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        sca_exponent = arcpy.Parameter(\n            displayName=\"Specific Contributing Area (SCA) Exponent\",\n            name=\"sca_exponent\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        sca_exponent.value = '0.4'\n\n        slope_exponent = arcpy.Parameter(\n            displayName=\"Slope Exponent\",\n            name=\"slope_exponent\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        slope_exponent.value = '1.3'\n\n        params = [sca, slope, output, sca_exponent, slope_exponent]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        sca = parameters[0].valueAsText\n        if sca is not None:\n            desc = arcpy.Describe(sca)\n            sca = desc.catalogPath\n        slope = parameters[1].valueAsText\n        if slope is not None:\n            desc = arcpy.Describe(slope)\n            slope = desc.catalogPath\n        output = parameters[2].valueAsText\n        sca_exponent = parameters[3].valueAsText\n        slope_exponent = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.sediment_transport_index(sca=sca, slope=slope, output=output, sca_exponent=sca_exponent, slope_exponent=slope_exponent)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SelectTilesByPolygon(object):\n    def __init__(self):\n        self.label = \"Select Tiles By Polygon\"\n        self.description = \"Copies LiDAR tiles overlapping with a polygon into an output directory.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        indir = arcpy.Parameter(\n            displayName=\"Input Directory\",\n            name=\"indir\",\n            datatype=\"DEFolder\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        outdir = arcpy.Parameter(\n            displayName=\"Output Directory\",\n            name=\"outdir\",\n            datatype=\"DEFolder\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        polygons = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"polygons\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        polygons.filter.list = [\"Polygon\"]\n\n        params = [indir, outdir, polygons]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        indir = parameters[0].valueAsText\n        outdir = parameters[1].valueAsText\n        polygons = parameters[2].valueAsText\n        if polygons is not None:\n            desc = arcpy.Describe(polygons)\n            polygons = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.select_tiles_by_polygon(indir=indir, outdir=outdir, polygons=polygons)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SetNodataValue(object):\n    def __init__(self):\n        self.label = \"Set Nodata Value\"\n        self.description = \"Assign the NoData value for an input image.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        back_value = arcpy.Parameter(\n            displayName=\"Background Value\",\n            name=\"back_value\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        back_value.value = '0.0'\n\n        params = [i, output, back_value]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        back_value = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.set_nodata_value(i=i, output=output, back_value=back_value)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ShadowAnimation(object):\n    def __init__(self):\n        self.label = \"Shadow Animation\"\n        self.description = \"This tool creates an animated GIF of shadows based on an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Digital Surface Model (DSM) Raster\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        palette = arcpy.Parameter(\n            displayName=\"DSM Palette\",\n            name=\"palette\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        palette.filter.type = \"ValueList\"\n        palette.filter.list = ['atlas', 'high_relief', 'arid', 'soft', 'muted', 'light_quant', 'purple', 'viridi', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep', 'none']\n        palette.value = 'atlas'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File (*.html)\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        max_dist = arcpy.Parameter(\n            displayName=\"Maximum Search Distance (xy units)\",\n            name=\"max_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        date = arcpy.Parameter(\n            displayName=\"Date (DD/MM/YYYY)\",\n            name=\"date\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        date.value = '21/06/2021'\n\n        interval = arcpy.Parameter(\n            displayName=\"Time Interval (in minutes)\",\n            name=\"interval\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        interval.value = '15'\n\n        location = arcpy.Parameter(\n            displayName=\"Lat/Long/UTC-offset (e.g. 43.5448/-80.2482/-4)\",\n            name=\"location\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        location.value = '43.5448/-80.2482/-4'\n\n        height = arcpy.Parameter(\n            displayName=\"Image Height (in pixels)\",\n            name=\"height\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        height.value = '600'\n\n        delay = arcpy.Parameter(\n            displayName=\"Delay (in milliseconds)\",\n            name=\"delay\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        delay.value = '250'\n\n        label = arcpy.Parameter(\n            displayName=\"Label text (blank for none)\",\n            name=\"label\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        params = [i, palette, output, max_dist, date, interval, location, height, delay, label]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        palette = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        max_dist = parameters[3].valueAsText\n        date = parameters[4].valueAsText\n        interval = parameters[5].valueAsText\n        location = parameters[6].valueAsText\n        height = parameters[7].valueAsText\n        delay = parameters[8].valueAsText\n        label = parameters[9].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.shadow_animation(i=i, palette=palette, output=output, max_dist=max_dist, date=date, interval=interval, location=location, height=height, delay=delay, label=label)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ShadowImage(object):\n    def __init__(self):\n        self.label = \"Shadow Image\"\n        self.description = \"This tool creates a raster of shadow areas based on an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Digital Surface Model (DSM) Raster\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        palette = arcpy.Parameter(\n            displayName=\"DSM Palette\",\n            name=\"palette\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        palette.filter.type = \"ValueList\"\n        palette.filter.list = ['atlas', 'high_relief', 'arid', 'soft', 'muted', 'light_quant', 'purple', 'viridis', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep', 'none']\n        palette.value = 'soft'\n\n        max_dist = arcpy.Parameter(\n            displayName=\"Maximum Search Distance (xy units)\",\n            name=\"max_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        date = arcpy.Parameter(\n            displayName=\"Date (DD/MM/YYYY)\",\n            name=\"date\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        date.value = '21/06/2021'\n\n        time = arcpy.Parameter(\n            displayName=\"Time (HH:MM, e.g. 03:15AM or 14:30)\",\n            name=\"time\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        time.value = '13:00'\n\n        location = arcpy.Parameter(\n            displayName=\"Lat/Long/UTC-offset (e.g. 43.5448/-80.2482/-4)\",\n            name=\"location\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        location.value = '43.5448/-80.2482/-4'\n\n        params = [i, output, palette, max_dist, date, time, location]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        palette = parameters[2].valueAsText\n        max_dist = parameters[3].valueAsText\n        date = parameters[4].valueAsText\n        time = parameters[5].valueAsText\n        location = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.shadow_image(i=i, output=output, palette=palette, max_dist=max_dist, date=date, time=time, location=location)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ShapeComplexityIndex(object):\n    def __init__(self):\n        self.label = \"Shape Complexity Index\"\n        self.description = \"Calculates overall polygon shape complexity or irregularity.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        params = [i]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.shape_complexity_index(i=i)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ShapeComplexityIndexRaster(object):\n    def __init__(self):\n        self.label = \"Shape Complexity Index Raster\"\n        self.description = \"Calculates the complexity of raster polygons or classes.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.shape_complexity_index_raster(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ShapeIndex(object):\n    def __init__(self):\n        self.label = \"Shape Index\"\n        self.description = \"This tool calculates the shape index from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        zfactor = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.shape_index(dem=dem, output=output, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ShreveStreamMagnitude(object):\n    def __init__(self):\n        self.label = \"Shreve Stream Magnitude\"\n        self.description = \"Assigns the Shreve stream magnitude to each link in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.shreve_stream_magnitude(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SigmoidalContrastStretch(object):\n    def __init__(self):\n        self.label = \"Sigmoidal Contrast Stretch\"\n        self.description = \"Performs a sigmoidal contrast stretch on input images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        cutoff = arcpy.Parameter(\n            displayName=\"Cutoff Value (0.0 - 0.95)\",\n            name=\"cutoff\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        cutoff.value = '0.0'\n\n        gain = arcpy.Parameter(\n            displayName=\"Gain Value\",\n            name=\"gain\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        gain.value = '1.0'\n\n        num_tones = arcpy.Parameter(\n            displayName=\"Number of Tones\",\n            name=\"num_tones\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_tones.value = '256'\n\n        params = [i, output, cutoff, gain, num_tones]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        cutoff = parameters[2].valueAsText\n        gain = parameters[3].valueAsText\n        num_tones = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.sigmoidal_contrast_stretch(i=i, output=output, cutoff=cutoff, gain=gain, num_tones=num_tones)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Sin(object):\n    def __init__(self):\n        self.label = \"Sin\"\n        self.description = \"Returns the sine (sin) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.sin(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SinglePartToMultiPart(object):\n    def __init__(self):\n        self.label = \"Single Part To Multi Part\"\n        self.description = \"Converts a vector file containing multi-part features into a vector containing only single-part features.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Line or Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        field = arcpy.Parameter(\n            displayName=\"Grouping ID Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Line or Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, field, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.single_part_to_multi_part(i=i, field=field, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Sinh(object):\n    def __init__(self):\n        self.label = \"Sinh\"\n        self.description = \"Returns the hyperbolic sine (sinh) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.sinh(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Sink(object):\n    def __init__(self):\n        self.label = \"Sink\"\n        self.description = \"Identifies the depressions in a DEM, giving each feature a unique identifier.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        input = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"input\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [input, output, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        zero_background = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.sink(i=i, output=output, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Slope(object):\n    def __init__(self):\n        self.label = \"Slope\"\n        self.description = \"Calculates a slope raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        units = arcpy.Parameter(\n            displayName=\"Units\",\n            name=\"units\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        units.filter.type = \"ValueList\"\n        units.filter.list = ['degrees', 'radians', 'percent']\n        units.value = 'degrees'\n\n        params = [dem, output, zfactor, units]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        zfactor = parameters[2].valueAsText\n        units = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.slope(dem=dem, output=output, zfactor=zfactor, units=units)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SlopeVsAspectPlot(object):\n    def __init__(self):\n        self.label = \"Slope Vs Aspect Plot\"\n        self.description = \"This tool creates a slope-aspect relation plot from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Raster Image\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File (*.html)\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        bin_size = arcpy.Parameter(\n            displayName=\"Aspect Bin Size (degrees)\",\n            name=\"bin_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        bin_size.value = '2.0'\n\n        min_slope = arcpy.Parameter(\n            displayName=\"Minimum Slope (degrees)\",\n            name=\"min_slope\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_slope.value = '0.1'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [i, output, bin_size, min_slope, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        bin_size = parameters[2].valueAsText\n        min_slope = parameters[3].valueAsText\n        zfactor = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.slope_vs_aspect_plot(i=i, output=output, bin_size=bin_size, min_slope=min_slope, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SlopeVsElevationPlot(object):\n    def __init__(self):\n        self.label = \"Slope Vs Elevation Plot\"\n        self.description = \"Creates a slope vs. elevation plot for one or more DEMs.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input DEM Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        watershed = arcpy.Parameter(\n            displayName=\"Input Watershed Files (optional)\",\n            name=\"watershed\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        watershed.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output HTML File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        params = [inputs, watershed, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        watershed = parameters[1].valueAsText\n        if watershed is not None:\n            items = watershed.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            watershed = \";\".join(items_path)\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.slope_vs_elevation_plot(inputs=inputs, watershed=watershed, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SmoothVectors(object):\n    def __init__(self):\n        self.label = \"Smooth Vectors\"\n        self.description = \"Smooths a vector coverage of either a POLYLINE or POLYGON base ShapeType.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Size\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '3'\n\n        params = [i, output, filter]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.smooth_vectors(i=i, output=output, filter=filter)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SmoothVegetationResidual(object):\n    def __init__(self):\n        self.label = \"Smooth Vegetation Residual\"\n        self.description = \"This tool can smooth the residual roughness due to vegetation cover in LiDAR DEMs.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Digital Elevation Model (DEM) Raster\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        max_scale = arcpy.Parameter(\n            displayName=\"Maximum Search Neighbourhood Radius (grid cells)\",\n            name=\"max_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_scale.value = '30'\n\n        dev_threshold = arcpy.Parameter(\n            displayName=\"DEVmax Threshold\",\n            name=\"dev_threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        dev_threshold.value = '1.0'\n\n        scale_threshold = arcpy.Parameter(\n            displayName=\"DEVmax Scale Threshold\",\n            name=\"scale_threshold\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        scale_threshold.value = '5'\n\n        params = [i, output, max_scale, dev_threshold, scale_threshold]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        max_scale = parameters[2].valueAsText\n        dev_threshold = parameters[3].valueAsText\n        scale_threshold = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.smooth_vegetation_residual(i=i, output=output, max_scale=max_scale, dev_threshold=dev_threshold, scale_threshold=scale_threshold)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SnapPourPoints(object):\n    def __init__(self):\n        self.label = \"Snap Pour Points\"\n        self.description = \"Moves outlet points used to specify points of interest in a watershedding operation to the cell with the highest flow accumulation in its neighbourhood.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        pour_pts = arcpy.Parameter(\n            displayName=\"Input Pour Points (Outlet) File\",\n            name=\"pour_pts\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        pour_pts.filter.list = [\"Point\"]\n\n        flow_accum = arcpy.Parameter(\n            displayName=\"Input D8 Flow Accumulation File\",\n            name=\"flow_accum\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        snap_dist = arcpy.Parameter(\n            displayName=\"Maximum Snap Distance (map units)\",\n            name=\"snap_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [pour_pts, flow_accum, output, snap_dist]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        pour_pts = parameters[0].valueAsText\n        if pour_pts is not None:\n            desc = arcpy.Describe(pour_pts)\n            pour_pts = desc.catalogPath\n        flow_accum = parameters[1].valueAsText\n        if flow_accum is not None:\n            desc = arcpy.Describe(flow_accum)\n            flow_accum = desc.catalogPath\n        output = parameters[2].valueAsText\n        snap_dist = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.snap_pour_points(pour_pts=pour_pts, flow_accum=flow_accum, output=output, snap_dist=snap_dist)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SobelFilter(object):\n    def __init__(self):\n        self.label = \"Sobel Filter\"\n        self.description = \"Performs a Sobel edge-detection filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        variant = arcpy.Parameter(\n            displayName=\"Variant\",\n            name=\"variant\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        variant.filter.type = \"ValueList\"\n        variant.filter.list = ['3x3', '5x5']\n        variant.value = '3x3'\n\n        clip = arcpy.Parameter(\n            displayName=\"Clip Tails (%)\",\n            name=\"clip\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        clip.value = '0.0'\n\n        params = [i, output, variant, clip]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        variant = parameters[2].valueAsText\n        clip = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.sobel_filter(i=i, output=output, variant=variant, clip=clip)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SortLidar(object):\n    def __init__(self):\n        self.label = \"Sort Lidar\"\n        self.description = \"Sorts LiDAR points based on their properties.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output LiDAR Points\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Output\")\n\n        criteria = arcpy.Parameter(\n            displayName=\"Sort Criteria:\",\n            name=\"criteria\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        params = [i, output, criteria]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        output = parameters[1].valueAsText\n        criteria = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.sort_lidar(i=i, output=output, criteria=criteria)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SphericalStdDevOfNormals(object):\n    def __init__(self):\n        self.label = \"Spherical Std Dev Of Normals\"\n        self.description = \"Calculates the spherical standard deviation of surface normals for a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filter = arcpy.Parameter(\n            displayName=\"Filter Dimension\",\n            name=\"filter\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filter.value = '11'\n\n        params = [dem, output, filter]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        filter = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.spherical_std_dev_of_normals(dem=dem, output=output, filter=filter)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SplitColourComposite(object):\n    def __init__(self):\n        self.label = \"Split Colour Composite\"\n        self.description = \"Splits an RGB colour composite image into separate multispectral images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Colour Composite Image File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        red = arcpy.Parameter(\n            displayName=\"Output Red Band File\",\n            name=\"red\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        red.filter.list = [\"tif\"]\n\n        green = arcpy.Parameter(\n            displayName=\"Output Green Band File\",\n            name=\"green\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        green.filter.list = [\"tif\"]\n\n        blue = arcpy.Parameter(\n            displayName=\"Output Blue Band File\",\n            name=\"blue\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        blue.filter.list = [\"tif\"]\n\n        params = [i, red, green, blue]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        red = parameters[1].valueAsText\n        green = parameters[2].valueAsText\n        blue = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.split_colour_composite(i=i, red=red, green=green, blue=blue)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SplitLidar(object):\n    def __init__(self):\n        self.label = \"Split Lidar\"\n        self.description = \"Splits LiDAR points up into a series of new files based on their properties.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input LiDAR Points\",\n            name=\"i\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        i.filter.list = [\"las\", \"zip\"]\n\n        criterion = arcpy.Parameter(\n            displayName=\"Split Criterion\",\n            name=\"criterion\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        criterion.filter.type = \"ValueList\"\n        criterion.filter.list = ['num_pts', 'x', 'y', 'z', 'intensity', 'class', 'user_data', 'point_source_id', 'scan_angle', 'time']\n        criterion.value = 'num_pts'\n\n        interval = arcpy.Parameter(\n            displayName=\"Interval\",\n            name=\"interval\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_pts = arcpy.Parameter(\n            displayName=\"Minimum Number of Points\",\n            name=\"min_pts\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_pts.value = '5'\n\n        params = [i, criterion, interval, min_pts]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        criterion = parameters[1].valueAsText\n        interval = parameters[2].valueAsText\n        min_pts = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.split_lidar(i=i, criterion=criterion, interval=interval, min_pts=min_pts)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SplitVectorLines(object):\n    def __init__(self):\n        self.label = \"Split Vector Lines\"\n        self.description = \"Used to split a vector line coverage into even-lengthed segments.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Lines\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Lines\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        length = arcpy.Parameter(\n            displayName=\"Max Segment Length\",\n            name=\"length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, length]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        length = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.split_vector_lines(i=i, output=output, length=length)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SplitWithLines(object):\n    def __init__(self):\n        self.label = \"Split With Lines\"\n        self.description = \"Splits the lines or polygons in one layer using the lines in another layer.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Lines or Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        split = arcpy.Parameter(\n            displayName=\"Input Vector Lines File\",\n            name=\"split\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        split.filter.list = [\"Polyline\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, split, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        split = parameters[1].valueAsText\n        if split is not None:\n            desc = arcpy.Describe(split)\n            split = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.split_with_lines(i=i, split=split, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Square(object):\n    def __init__(self):\n        self.label = \"Square\"\n        self.description = \"Squares the values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.square(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SquareRoot(object):\n    def __init__(self):\n        self.label = \"Square Root\"\n        self.description = \"Returns the square root of the values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.square_root(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StandardDeviationContrastStretch(object):\n    def __init__(self):\n        self.label = \"Standard Deviation Contrast Stretch\"\n        self.description = \"Performs a standard-deviation contrast stretch on input images.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        stdev = arcpy.Parameter(\n            displayName=\"Standard Deviation Threshold\",\n            name=\"stdev\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        stdev.value = '2.0'\n\n        num_tones = arcpy.Parameter(\n            displayName=\"Number of Tones\",\n            name=\"num_tones\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        num_tones.value = '256'\n\n        params = [i, output, stdev, num_tones]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        stdev = parameters[2].valueAsText\n        num_tones = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.standard_deviation_contrast_stretch(i=i, output=output, stdev=stdev, num_tones=num_tones)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StandardDeviationFilter(object):\n    def __init__(self):\n        self.label = \"Standard Deviation Filter\"\n        self.description = \"Assigns each cell in the output grid the standard deviation of values in a moving window centred on each grid cell in the input raster.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.standard_deviation_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StandardDeviationOfSlope(object):\n    def __init__(self):\n        self.label = \"Standard Deviation Of Slope\"\n        self.description = \"Calculates the standard deviation of slope from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, zfactor, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        zfactor = parameters[2].valueAsText\n        filterx = parameters[3].valueAsText\n        filtery = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.standard_deviation_of_slope(i=i, output=output, zfactor=zfactor, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StochasticDepressionAnalysis(object):\n    def __init__(self):\n        self.label = \"Stochastic Depression Analysis\"\n        self.description = \"Performs a stochastic analysis of depressions within a DEM.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        rmse = arcpy.Parameter(\n            displayName=\"DEM root-mean-square-error (z units)\",\n            name=\"rmse\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        range = arcpy.Parameter(\n            displayName=\"Range of Autocorrelation (map units)\",\n            name=\"range\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        iterations = arcpy.Parameter(\n            displayName=\"Iterations\",\n            name=\"iterations\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        iterations.value = '100'\n\n        params = [dem, output, rmse, range, iterations]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        rmse = parameters[2].valueAsText\n        range = parameters[3].valueAsText\n        iterations = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.stochastic_depression_analysis(dem=dem, output=output, rmse=rmse, range=range, iterations=iterations)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StrahlerOrderBasins(object):\n    def __init__(self):\n        self.label = \"Strahler Order Basins\"\n        self.description = \"Identifies Strahler-order basins from an input stream network.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, streams, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.strahler_order_basins(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StrahlerStreamOrder(object):\n    def __init__(self):\n        self.label = \"Strahler Stream Order\"\n        self.description = \"Assigns the Strahler stream order to each link in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.strahler_stream_order(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StreamLinkClass(object):\n    def __init__(self):\n        self.label = \"Stream Link Class\"\n        self.description = \"Identifies the exterior/interior links and nodes in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.stream_link_class(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StreamLinkIdentifier(object):\n    def __init__(self):\n        self.label = \"Stream Link Identifier\"\n        self.description = \"Assigns a unique identifier to each link in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.stream_link_identifier(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StreamLinkLength(object):\n    def __init__(self):\n        self.label = \"Stream Link Length\"\n        self.description = \"Estimates the length of each link (or tributary) in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        linkid = arcpy.Parameter(\n            displayName=\"Input Stream Link (Tributary) ID File\",\n            name=\"linkid\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, linkid, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        linkid = parameters[1].valueAsText\n        if linkid is not None:\n            desc = arcpy.Describe(linkid)\n            linkid = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.stream_link_length(d8_pntr=d8_pntr, linkid=linkid, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StreamLinkSlope(object):\n    def __init__(self):\n        self.label = \"Stream Link Slope\"\n        self.description = \"Estimates the average slope of each link (or tributary) in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        linkid = arcpy.Parameter(\n            displayName=\"Input Stream Link (Tributary) ID File\",\n            name=\"linkid\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, linkid, dem, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        linkid = parameters[1].valueAsText\n        if linkid is not None:\n            desc = arcpy.Describe(linkid)\n            linkid = desc.catalogPath\n        dem = parameters[2].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[3].valueAsText\n        esri_pntr = parameters[4].valueAsText\n        zero_background = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.stream_link_slope(d8_pntr=d8_pntr, linkid=linkid, dem=dem, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StreamPowerIndex(object):\n    def __init__(self):\n        self.label = \"Stream Power Index\"\n        self.description = \"Calculates the relative stream power index.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        sca = arcpy.Parameter(\n            displayName=\"Input Specific Contributing Area (SCA) File\",\n            name=\"sca\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        slope = arcpy.Parameter(\n            displayName=\"Input Slope File\",\n            name=\"slope\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        exponent = arcpy.Parameter(\n            displayName=\"Specific Contributing Area (SCA) Exponent\",\n            name=\"exponent\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        exponent.value = '1.0'\n\n        params = [sca, slope, output, exponent]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        sca = parameters[0].valueAsText\n        if sca is not None:\n            desc = arcpy.Describe(sca)\n            sca = desc.catalogPath\n        slope = parameters[1].valueAsText\n        if slope is not None:\n            desc = arcpy.Describe(slope)\n            slope = desc.catalogPath\n        output = parameters[2].valueAsText\n        exponent = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.stream_power_index(sca=sca, slope=slope, output=output, exponent=exponent)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass StreamSlopeContinuous(object):\n    def __init__(self):\n        self.label = \"Stream Slope Continuous\"\n        self.description = \"Estimates the slope of each grid cell in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, dem, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        dem = parameters[2].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[3].valueAsText\n        esri_pntr = parameters[4].valueAsText\n        zero_background = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.stream_slope_continuous(d8_pntr=d8_pntr, streams=streams, dem=dem, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Subbasins(object):\n    def __init__(self):\n        self.label = \"Subbasins\"\n        self.description = \"Identifies the catchments, or sub-basin, draining to each link in a stream network.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, streams, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.subbasins(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Subtract(object):\n    def __init__(self):\n        self.label = \"Subtract\"\n        self.description = \"Performs a differencing operation on two rasters or a raster and a constant value.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input1\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File Or Constant Value\",\n            name=\"input2\",\n            datatype=[\"GPRasterLayer\", \"GPDouble\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            try:\n                input1 = str(float(input1))\n            except:\n                desc = arcpy.Describe(input1)\n                input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            try:\n                input2 = str(float(input2))\n            except:\n                desc = arcpy.Describe(input2)\n                input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.subtract(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SumOverlay(object):\n    def __init__(self):\n        self.label = \"Sum Overlay\"\n        self.description = \"Calculates the sum for each grid cell from a group of raster images.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.sum_overlay(inputs=inputs, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SurfaceAreaRatio(object):\n    def __init__(self):\n        self.label = \"Surface Area Ratio\"\n        self.description = \"Calculates a the surface area ratio of each grid cell in an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.surface_area_ratio(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SvmClassification(object):\n    def __init__(self):\n        self.label = \"Svm Classification\"\n        self.description = \"Performs an SVM binary classification using training site polygons/points and multiple input images.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Predictor Rasters\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        scaling = arcpy.Parameter(\n            displayName=\"Scaling Method\",\n            name=\"scaling\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        scaling.filter.type = \"ValueList\"\n        scaling.filter.list = ['None', 'Normalize', 'Standardize']\n        scaling.value = 'Normalize'\n\n        training = arcpy.Parameter(\n            displayName=\"Input Training Polygons/Points\",\n            name=\"training\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        field = arcpy.Parameter(\n            displayName=\"Class Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [training.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        c = arcpy.Parameter(\n            displayName=\"c-Value\",\n            name=\"c\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        c.value = '200.0'\n\n        gamma = arcpy.Parameter(\n            displayName=\"Kernel Gamma\",\n            name=\"gamma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        gamma.value = '50.0'\n\n        tolerance = arcpy.Parameter(\n            displayName=\"Tolerance\",\n            name=\"tolerance\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        tolerance.value = '0.1'\n\n        test_proportion = arcpy.Parameter(\n            displayName=\"Test Proportion\",\n            name=\"test_proportion\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        test_proportion.value = '0.2'\n\n        params = [inputs, scaling, training, field, output, c, gamma, tolerance, test_proportion]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        scaling = parameters[1].valueAsText\n        training = parameters[2].valueAsText\n        if training is not None:\n            desc = arcpy.Describe(training)\n            training = desc.catalogPath\n        field = parameters[3].valueAsText\n        output = parameters[4].valueAsText\n        c = parameters[5].valueAsText\n        gamma = parameters[6].valueAsText\n        tolerance = parameters[7].valueAsText\n        test_proportion = parameters[8].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.svm_classification(inputs=inputs, scaling=scaling, training=training, field=field, output=output, c=c, gamma=gamma, tolerance=tolerance, test_proportion=test_proportion)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SvmRegression(object):\n    def __init__(self):\n        self.label = \"Svm Regression\"\n        self.description = \"Performs a supervised SVM regression analysis using training site points and predictor rasters.\"\n        self.category = \"Machine Learning\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Predictor Rasters\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        scaling = arcpy.Parameter(\n            displayName=\"Scaling Method\",\n            name=\"scaling\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        scaling.filter.type = \"ValueList\"\n        scaling.filter.list = ['None', 'Normalize', 'Standardize']\n        scaling.value = 'Normalize'\n\n        training = arcpy.Parameter(\n            displayName=\"Input Training Polygons/Points\",\n            name=\"training\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        training.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Class Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [training.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        c = arcpy.Parameter(\n            displayName=\"c-Value\",\n            name=\"c\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        c.value = '50.0'\n\n        eps = arcpy.Parameter(\n            displayName=\"Epsilon Value\",\n            name=\"eps\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        eps.value = '10.0'\n\n        gamma = arcpy.Parameter(\n            displayName=\"Kernel Gamma\",\n            name=\"gamma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        gamma.value = '0.5'\n\n        test_proportion = arcpy.Parameter(\n            displayName=\"Test Proportion\",\n            name=\"test_proportion\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        test_proportion.value = '0.2'\n\n        params = [inputs, scaling, training, field, output, c, eps, gamma, test_proportion]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        scaling = parameters[1].valueAsText\n        training = parameters[2].valueAsText\n        if training is not None:\n            desc = arcpy.Describe(training)\n            training = desc.catalogPath\n        field = parameters[3].valueAsText\n        output = parameters[4].valueAsText\n        c = parameters[5].valueAsText\n        eps = parameters[6].valueAsText\n        gamma = parameters[7].valueAsText\n        test_proportion = parameters[8].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.svm_regression(inputs=inputs, scaling=scaling, training=training, field=field, output=output, c=c, eps=eps, gamma=gamma, test_proportion=test_proportion)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass SymmetricalDifference(object):\n    def __init__(self):\n        self.label = \"Symmetrical Difference\"\n        self.description = \"Outputs the features that occur in one of the two vector inputs but not both, i.e. no overlapping features.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        overlay = arcpy.Parameter(\n            displayName=\"Input Overlay Vector File\",\n            name=\"overlay\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        snap = arcpy.Parameter(\n            displayName=\"Snap Tolerance\",\n            name=\"snap\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        snap.value = '0.0'\n\n        params = [i, overlay, output, snap]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        overlay = parameters[1].valueAsText\n        if overlay is not None:\n            desc = arcpy.Describe(overlay)\n            overlay = desc.catalogPath\n        output = parameters[2].valueAsText\n        snap = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.symmetrical_difference(i=i, overlay=overlay, output=output, snap=snap)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TinGridding(object):\n    def __init__(self):\n        self.label = \"Tin Gridding\"\n        self.description = \"Creates a raster grid based on a triangular irregular network (TIN) fitted to vector points.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        use_z = arcpy.Parameter(\n            displayName=\"Use Shapefile 'z' values?\",\n            name=\"use_z\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        use_z.value = 'False'\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        resolution = arcpy.Parameter(\n            displayName=\"Grid Resolution\",\n            name=\"resolution\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        max_triangle_edge_length = arcpy.Parameter(\n            displayName=\"Maximum Triangle Edge Length (optional)\",\n            name=\"max_triangle_edge_length\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, use_z, output, resolution, base, max_triangle_edge_length]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        use_z = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        resolution = parameters[4].valueAsText\n        base = parameters[5].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        max_triangle_edge_length = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.tin_gridding(i=i, field=field, use_z=use_z, output=output, resolution=resolution, base=base, max_triangle_edge_length=max_triangle_edge_length)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Tan(object):\n    def __init__(self):\n        self.label = \"Tan\"\n        self.description = \"Returns the tangent (tan) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.tan(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TangentialCurvature(object):\n    def __init__(self):\n        self.label = \"Tangential Curvature\"\n        self.description = \"Calculates a tangential curvature raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.tangential_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Tanh(object):\n    def __init__(self):\n        self.label = \"Tanh\"\n        self.description = \"Returns the hyperbolic tangent (tanh) of each values in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.tanh(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ThickenRasterLine(object):\n    def __init__(self):\n        self.label = \"Thicken Raster Line\"\n        self.description = \"Thickens single-cell wide lines within a raster image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.thicken_raster_line(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TimeInDaylight(object):\n    def __init__(self):\n        self.label = \"Time In Daylight\"\n        self.description = \"Calculates the proportion of time a location is not within an area of shadow.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        az_fraction = arcpy.Parameter(\n            displayName=\"Azimuth Fraction\",\n            name=\"az_fraction\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        az_fraction.value = '10.0'\n\n        max_dist = arcpy.Parameter(\n            displayName=\"Maximum Search Distance\",\n            name=\"max_dist\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        max_dist.value = '100.0'\n\n        lat = arcpy.Parameter(\n            displayName=\"Centre Point Latitude\",\n            name=\"lat\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        long = arcpy.Parameter(\n            displayName=\"Centre Point Longitude\",\n            name=\"long\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        utc_offset = arcpy.Parameter(\n            displayName=\"UTC Offset (e.g. -04:00, +06:00)\",\n            name=\"utc_offset\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        utc_offset.value = '00:00'\n\n        start_day = arcpy.Parameter(\n            displayName=\"Start Day Of The Year (1-365)\",\n            name=\"start_day\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        start_day.value = '1'\n\n        end_day = arcpy.Parameter(\n            displayName=\"End Day Of The Year (1-365)\",\n            name=\"end_day\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        end_day.value = '365'\n\n        start_time = arcpy.Parameter(\n            displayName=\"Starting Hour (24-hour time: HH:MM:SS e.g. 05:00:00)\",\n            name=\"start_time\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        start_time.value = '00:00:00'\n\n        end_time = arcpy.Parameter(\n            displayName=\"Ending Hour (24-hour time: HH:MM:SS e.g. 21:00:00)\",\n            name=\"end_time\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        end_time.value = '23:59:59'\n\n        params = [dem, output, az_fraction, max_dist, lat, long, utc_offset, start_day, end_day, start_time, end_time]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        az_fraction = parameters[2].valueAsText\n        max_dist = parameters[3].valueAsText\n        lat = parameters[4].valueAsText\n        long = parameters[5].valueAsText\n        utc_offset = parameters[6].valueAsText\n        start_day = parameters[7].valueAsText\n        end_day = parameters[8].valueAsText\n        start_time = parameters[9].valueAsText\n        end_time = parameters[10].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.time_in_daylight(dem=dem, output=output, az_fraction=az_fraction, max_dist=max_dist, lat=lat, long=long, utc_offset=utc_offset, start_day=start_day, end_day=end_day, start_time=start_time, end_time=end_time)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ToDegrees(object):\n    def __init__(self):\n        self.label = \"To Degrees\"\n        self.description = \"Converts a raster from radians to degrees.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.to_degrees(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ToRadians(object):\n    def __init__(self):\n        self.label = \"To Radians\"\n        self.description = \"Converts a raster from degrees to radians.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.to_radians(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TophatTransform(object):\n    def __init__(self):\n        self.label = \"Tophat Transform\"\n        self.description = \"Performs either a white or black top-hat transform on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        variant = arcpy.Parameter(\n            displayName=\"Variant\",\n            name=\"variant\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        variant.filter.type = \"ValueList\"\n        variant.filter.list = ['white', 'black']\n        variant.value = 'white'\n\n        params = [i, output, filterx, filtery, variant]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        variant = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.tophat_transform(i=i, output=output, filterx=filterx, filtery=filtery, variant=variant)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TopoRender(object):\n    def __init__(self):\n        self.label = \"Topo Render\"\n        self.description = \"This tool creates a pseudo-3D rendering from an input DEM, for the purpose of effective topographic visualization.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Digital Elevation Model (DEM) Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        palette = arcpy.Parameter(\n            displayName=\"Palette\",\n            name=\"palette\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        palette.filter.type = \"ValueList\"\n        palette.filter.list = ['atlas', 'high_relief', 'arid', 'soft', 'earthtones', 'muted', 'light_quant', 'purple', 'viridis', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep', 'imhof', 'white']\n        palette.value = 'soft'\n\n        rev_palette = arcpy.Parameter(\n            displayName=\"Reverse the palette?\",\n            name=\"rev_palette\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        rev_palette.value = 'False'\n\n        az = arcpy.Parameter(\n            displayName=\"Light Source Direction (degrees)\",\n            name=\"az\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        az.value = '315.0'\n\n        alt = arcpy.Parameter(\n            displayName=\"Light Source Altitude (degrees)\",\n            name=\"alt\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        alt.value = '30.0'\n\n        background_hgt_offset = arcpy.Parameter(\n            displayName=\"Offset Height of Background (z-units)\",\n            name=\"background_hgt_offset\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        background_hgt_offset.value = '10.0'\n\n        polygon = arcpy.Parameter(\n            displayName=\"Clipping Polygon\",\n            name=\"polygon\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        polygon.filter.list = [\"Polygon\"]\n\n        background_clr = arcpy.Parameter(\n            displayName=\"Background RGB colour\",\n            name=\"background_clr\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        background_clr.value = '[255, 255, 255]'\n\n        attenuation = arcpy.Parameter(\n            displayName=\"Attenuation Parameter\",\n            name=\"attenuation\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        attenuation.value = '0.6'\n\n        ambient_light = arcpy.Parameter(\n            displayName=\"Ambient Light\",\n            name=\"ambient_light\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        ambient_light.value = '0.2'\n\n        z_factor = arcpy.Parameter(\n            displayName=\"Elevation Multiplier\",\n            name=\"z_factor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        z_factor.value = '1.0'\n\n        params = [dem, output, palette, rev_palette, az, alt, background_hgt_offset, polygon, background_clr, attenuation, ambient_light, z_factor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        palette = parameters[2].valueAsText\n        rev_palette = parameters[3].valueAsText\n        az = parameters[4].valueAsText\n        alt = parameters[5].valueAsText\n        background_hgt_offset = parameters[6].valueAsText\n        polygon = parameters[7].valueAsText\n        if polygon is not None:\n            desc = arcpy.Describe(polygon)\n            polygon = desc.catalogPath\n        background_clr = parameters[8].valueAsText\n        attenuation = parameters[9].valueAsText\n        ambient_light = parameters[10].valueAsText\n        z_factor = parameters[11].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.topo_render(dem=dem, output=output, palette=palette, rev_palette=rev_palette, az=az, alt=alt, background_hgt_offset=background_hgt_offset, polygon=polygon, background_clr=background_clr, attenuation=attenuation, ambient_light=ambient_light, z_factor=z_factor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TopographicPositionAnimation(object):\n    def __init__(self):\n        self.label = \"Topographic Position Animation\"\n        self.description = \"This tool creates an animated GIF of multi-scale local topographic position (elevation deviation).\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Digital Elevation Model (DEM) Raster\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        palette = arcpy.Parameter(\n            displayName=\"Palette\",\n            name=\"palette\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        palette.filter.type = \"ValueList\"\n        palette.filter.list = ['bl_yl_rd', 'bl_w_rd', 'purple', 'gn_yl', 'pi_y_g', 'viridis']\n        palette.value = 'bl_yl_rd'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File (*.html)\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        min_scale = arcpy.Parameter(\n            displayName=\"Minimum Search Neighbourhood Radius (grid cells)\",\n            name=\"min_scale\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_scale.value = '1'\n\n        num_steps = arcpy.Parameter(\n            displayName=\"Number of Steps\",\n            name=\"num_steps\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        num_steps.value = '100'\n\n        step_nonlinearity = arcpy.Parameter(\n            displayName=\"Step Nonlinearity\",\n            name=\"step_nonlinearity\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        step_nonlinearity.value = '1.5'\n\n        height = arcpy.Parameter(\n            displayName=\"Image Height (in pixels)\",\n            name=\"height\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        height.value = '600'\n\n        delay = arcpy.Parameter(\n            displayName=\"Delay (in milliseconds)\",\n            name=\"delay\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        delay.value = '250'\n\n        label = arcpy.Parameter(\n            displayName=\"Label text (blank for none)\",\n            name=\"label\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        dev_max = arcpy.Parameter(\n            displayName=\"Use DEVmax for topo position?\",\n            name=\"dev_max\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        dev_max.value = 'False'\n\n        params = [i, palette, output, min_scale, num_steps, step_nonlinearity, height, delay, label, dev_max]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        palette = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        min_scale = parameters[3].valueAsText\n        num_steps = parameters[4].valueAsText\n        step_nonlinearity = parameters[5].valueAsText\n        height = parameters[6].valueAsText\n        delay = parameters[7].valueAsText\n        label = parameters[8].valueAsText\n        dev_max = parameters[9].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.topographic_position_animation(i=i, palette=palette, output=output, min_scale=min_scale, num_steps=num_steps, step_nonlinearity=step_nonlinearity, height=height, delay=delay, label=label, dev_max=dev_max)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TopologicalStreamOrder(object):\n    def __init__(self):\n        self.label = \"Topological Stream Order\"\n        self.description = \"Assigns each link in a stream network its topological order.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.topological_stream_order(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TotalCurvature(object):\n    def __init__(self):\n        self.label = \"Total Curvature\"\n        self.description = \"Calculates a total curvature raster from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z Conversion Factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.total_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TotalFilter(object):\n    def __init__(self):\n        self.label = \"Total Filter\"\n        self.description = \"Performs a total filter on an input image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        filterx = arcpy.Parameter(\n            displayName=\"Filter X-Dimension\",\n            name=\"filterx\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filterx.value = '11'\n\n        filtery = arcpy.Parameter(\n            displayName=\"Filter Y-Dimension\",\n            name=\"filtery\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        filtery.value = '11'\n\n        params = [i, output, filterx, filtery]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        filterx = parameters[2].valueAsText\n        filtery = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.total_filter(i=i, output=output, filterx=filterx, filtery=filtery)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TraceDownslopeFlowpaths(object):\n    def __init__(self):\n        self.label = \"Trace Downslope Flowpaths\"\n        self.description = \"Traces downslope flowpaths from one or more target sites (i.e. seed points).\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        seed_pts = arcpy.Parameter(\n            displayName=\"Input Vector Seed Points File\",\n            name=\"seed_pts\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        seed_pts.filter.list = [\"Point\"]\n\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [seed_pts, d8_pntr, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        seed_pts = parameters[0].valueAsText\n        if seed_pts is not None:\n            desc = arcpy.Describe(seed_pts)\n            seed_pts = desc.catalogPath\n        d8_pntr = parameters[1].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.trace_downslope_flowpaths(seed_pts=seed_pts, d8_pntr=d8_pntr, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TravellingSalesmanProblem(object):\n    def __init__(self):\n        self.label = \"Travelling Salesman Problem\"\n        self.description = \"Finds approximate solutions to travelling salesman problems, the goal of which is to identify the shortest route connecting a set of locations.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Points\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Lines\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        duration = arcpy.Parameter(\n            displayName=\"Max Duration\",\n            name=\"duration\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        duration.value = '60'\n\n        params = [i, output, duration]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        duration = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.travelling_salesman_problem(i=i, output=output, duration=duration)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TrendSurface(object):\n    def __init__(self):\n        self.label = \"Trend Surface\"\n        self.description = \"Estimates the trend surface of an input raster file.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        order = arcpy.Parameter(\n            displayName=\"Polynomial Order\",\n            name=\"order\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        order.value = '1'\n\n        params = [i, output, order]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        order = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.trend_surface(i=i, output=output, order=order)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TrendSurfaceVectorPoints(object):\n    def __init__(self):\n        self.label = \"Trend Surface Vector Points\"\n        self.description = \"Estimates a trend surface from vector points.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        order = arcpy.Parameter(\n            displayName=\"Polynomial Order\",\n            name=\"order\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        order.value = '1'\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        params = [i, field, output, order, cell_size]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        order = parameters[3].valueAsText\n        cell_size = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.trend_surface_vector_points(i=i, field=field, output=output, order=order, cell_size=cell_size)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TributaryIdentifier(object):\n    def __init__(self):\n        self.label = \"Tributary Identifier\"\n        self.description = \"Assigns a unique identifier to each tributary in a stream network.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams File\",\n            name=\"streams\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        zero_background = arcpy.Parameter(\n            displayName=\"Should a background value of zero be used?\",\n            name=\"zero_background\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [d8_pntr, streams, output, esri_pntr, zero_background]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        streams = parameters[1].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        zero_background = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.tributary_identifier(d8_pntr=d8_pntr, streams=streams, output=output, esri_pntr=esri_pntr, zero_background=zero_background)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Truncate(object):\n    def __init__(self):\n        self.label = \"Truncate\"\n        self.description = \"Truncates the values in a raster to the desired number of decimal places.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        num_decimals = arcpy.Parameter(\n            displayName=\"Number of Decimals After Truncation\",\n            name=\"num_decimals\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, output, num_decimals]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        num_decimals = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.truncate(i=i, output=output, num_decimals=num_decimals)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TurningBandsSimulation(object):\n    def __init__(self):\n        self.label = \"Turning Bands Simulation\"\n        self.description = \"Creates an image containing random values based on a turning-bands simulation.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        base = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        range = arcpy.Parameter(\n            displayName=\"Range of Autocorrelation (map units)\",\n            name=\"range\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        iterations = arcpy.Parameter(\n            displayName=\"Iterations\",\n            name=\"iterations\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        iterations.value = '1000'\n\n        params = [base, output, range, iterations]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        base = parameters[0].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        output = parameters[1].valueAsText\n        range = parameters[2].valueAsText\n        iterations = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.turning_bands_simulation(base=base, output=output, range=range, iterations=iterations)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass TwoSampleKsTest(object):\n    def __init__(self):\n        self.label = \"Two Sample Ks Test\"\n        self.description = \"Performs a 2-sample K-S test for significant differences on two input rasters.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"First Input File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Second Input File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        num_samples = arcpy.Parameter(\n            displayName=\"Num. Samples (blank for while image)\",\n            name=\"num_samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [input1, input2, output, num_samples]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        num_samples = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.two_sample_ks_test(input1=input1, input2=input2, output=output, num_samples=num_samples)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Union(object):\n    def __init__(self):\n        self.label = \"Union\"\n        self.description = \"Splits vector layers at their overlaps, creating a layer containing all the portions from both input and overlay layers.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        overlay = arcpy.Parameter(\n            displayName=\"Input Overlay Vector File\",\n            name=\"overlay\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        snap = arcpy.Parameter(\n            displayName=\"Snap Tolerance\",\n            name=\"snap\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        snap.value = '0.0'\n\n        params = [i, overlay, output, snap]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        overlay = parameters[1].valueAsText\n        if overlay is not None:\n            desc = arcpy.Describe(overlay)\n            overlay = desc.catalogPath\n        output = parameters[2].valueAsText\n        snap = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.union(i=i, overlay=overlay, output=output, snap=snap)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass UnnestBasins(object):\n    def __init__(self):\n        self.label = \"Unnest Basins\"\n        self.description = \"Extract whole watersheds for a set of outlet points.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        pour_pts = arcpy.Parameter(\n            displayName=\"Input Pour Points (Outlet) File\",\n            name=\"pour_pts\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        pour_pts.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, pour_pts, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        pour_pts = parameters[1].valueAsText\n        if pour_pts is not None:\n            desc = arcpy.Describe(pour_pts)\n            pour_pts = desc.catalogPath\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.unnest_basins(d8_pntr=d8_pntr, pour_pts=pour_pts, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass UnsharpMasking(object):\n    def __init__(self):\n        self.label = \"Unsharp Masking\"\n        self.description = \"An image sharpening technique that enhances edges.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        sigma = arcpy.Parameter(\n            displayName=\"Standard Deviation (pixels)\",\n            name=\"sigma\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        sigma.value = '0.75'\n\n        amount = arcpy.Parameter(\n            displayName=\"Amount (%)\",\n            name=\"amount\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        amount.value = '100.0'\n\n        threshold = arcpy.Parameter(\n            displayName=\"Threshold\",\n            name=\"threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        threshold.value = '0.0'\n\n        params = [i, output, sigma, amount, threshold]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        sigma = parameters[2].valueAsText\n        amount = parameters[3].valueAsText\n        threshold = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.unsharp_masking(i=i, output=output, sigma=sigma, amount=amount, threshold=threshold)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Unsphericity(object):\n    def __init__(self):\n        self.label = \"Unsphericity\"\n        self.description = \"This tool calculates the unsphericity curvature from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.unsphericity(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass UpdateNodataCells(object):\n    def __init__(self):\n        self.label = \"Update Nodata Cells\"\n        self.description = \"Replaces the NoData values in an input raster with the corresponding values contained in a second update layer.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File 1\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File 2 (Update Layer)\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.update_nodata_cells(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass UpslopeDepressionStorage(object):\n    def __init__(self):\n        self.label = \"Upslope Depression Storage\"\n        self.description = \"Estimates the average upslope depression storage depth.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [dem, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.upslope_depression_storage(dem=dem, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass UserDefinedWeightsFilter(object):\n    def __init__(self):\n        self.label = \"User Defined Weights Filter\"\n        self.description = \"Performs a user-defined weights filter on an image.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        weights = arcpy.Parameter(\n            displayName=\"Input Weights File\",\n            name=\"weights\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        weights.filter.list = [\"csv\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        center = arcpy.Parameter(\n            displayName=\"Kernel Center\",\n            name=\"center\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        center.filter.type = \"ValueList\"\n        center.filter.list = ['center', 'upper-left', 'upper-right', 'lower-left', 'lower-right']\n        center.value = 'center'\n\n        normalize = arcpy.Parameter(\n            displayName=\"Normalize kernel weights?\",\n            name=\"normalize\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        normalize.value = 'False'\n\n        params = [i, weights, output, center, normalize]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        weights = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        center = parameters[3].valueAsText\n        normalize = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.user_defined_weights_filter(i=i, weights=weights, output=output, center=center, normalize=normalize)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass VectorHexBinning(object):\n    def __init__(self):\n        self.label = \"Vector Hex Binning\"\n        self.description = \"Hex-bins a set of vector points.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Base File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        width = arcpy.Parameter(\n            displayName=\"Hexagon Width\",\n            name=\"width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        orientation = arcpy.Parameter(\n            displayName=\"Grid Orientation\",\n            name=\"orientation\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        orientation.filter.type = \"ValueList\"\n        orientation.filter.list = ['horizontal', 'vertical']\n        orientation.value = 'horizontal'\n\n        params = [i, output, width, orientation]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        width = parameters[2].valueAsText\n        orientation = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.vector_hex_binning(i=i, output=output, width=width, orientation=orientation)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass VectorLinesToRaster(object):\n    def __init__(self):\n        self.label = \"Vector Lines To Raster\"\n        self.description = \"Converts a vector containing polylines into a raster.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Lines File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polyline\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n        field.value = 'FID'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        nodata = arcpy.Parameter(\n            displayName=\"Background value is NoData?\",\n            name=\"nodata\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        nodata.value = 'True'\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, output, nodata, cell_size, base]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        nodata = parameters[3].valueAsText\n        cell_size = parameters[4].valueAsText\n        base = parameters[5].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.vector_lines_to_raster(i=i, field=field, output=output, nodata=nodata, cell_size=cell_size, base=base)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass VectorPointsToRaster(object):\n    def __init__(self):\n        self.label = \"Vector Points To Raster\"\n        self.description = \"Converts a vector containing points into a raster.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n        field.value = 'FID'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        assign = arcpy.Parameter(\n            displayName=\"Assignment Operation\",\n            name=\"assign\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        assign.filter.type = \"ValueList\"\n        assign.filter.list = ['first', 'last', 'min', 'max', 'sum', 'number']\n        assign.value = 'last'\n\n        nodata = arcpy.Parameter(\n            displayName=\"Background value is NoData?\",\n            name=\"nodata\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        nodata.value = 'True'\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, output, assign, nodata, cell_size, base]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        assign = parameters[3].valueAsText\n        nodata = parameters[4].valueAsText\n        cell_size = parameters[5].valueAsText\n        base = parameters[6].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.vector_points_to_raster(i=i, field=field, output=output, assign=assign, nodata=nodata, cell_size=cell_size, base=base)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass VectorPolygonsToRaster(object):\n    def __init__(self):\n        self.label = \"Vector Polygons To Raster\"\n        self.description = \"Converts a vector containing polygons into a raster.\"\n        self.category = \"Data Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Polygon File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Polygon\"]\n\n        field = arcpy.Parameter(\n            displayName=\"Field Name\",\n            name=\"field\",\n            datatype=\"Field\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        field.parameterDependencies = [i.name]\n        field.value = 'FID'\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        nodata = arcpy.Parameter(\n            displayName=\"Background value is NoData?\",\n            name=\"nodata\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        nodata.value = 'True'\n\n        cell_size = arcpy.Parameter(\n            displayName=\"Cell Size (optional)\",\n            name=\"cell_size\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        base = arcpy.Parameter(\n            displayName=\"Base Raster File (optional)\",\n            name=\"base\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [i, field, output, nodata, cell_size, base]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        nodata = parameters[3].valueAsText\n        cell_size = parameters[4].valueAsText\n        base = parameters[5].valueAsText\n        if base is not None:\n            desc = arcpy.Describe(base)\n            base = desc.catalogPath\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.vector_polygons_to_raster(i=i, field=field, output=output, nodata=nodata, cell_size=cell_size, base=base)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass VectorStreamNetworkAnalysis(object):\n    def __init__(self):\n        self.label = \"Vector Stream Network Analysis\"\n        self.description = \"This tool performs common stream network analysis operations on an input vector stream file.\"\n        self.category = \"Stream Network Analysis\"\n\n    def getParameterInfo(self):\n        streams = arcpy.Parameter(\n            displayName=\"Input Streams Vector\",\n            name=\"streams\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        streams.filter.list = [\"Polyline\"]\n\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM Raster\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Lines\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        cutting_height = arcpy.Parameter(\n            displayName=\"Maximum Ridge-cutting Height (z units)\",\n            name=\"cutting_height\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        cutting_height.value = '10.0'\n\n        snap = arcpy.Parameter(\n            displayName=\"Snap Distance\",\n            name=\"snap\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        snap.value = '0.1'\n\n        params = [streams, dem, output, cutting_height, snap]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        streams = parameters[0].valueAsText\n        if streams is not None:\n            desc = arcpy.Describe(streams)\n            streams = desc.catalogPath\n        dem = parameters[1].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[2].valueAsText\n        cutting_height = parameters[3].valueAsText\n        snap = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.vector_stream_network_analysis(streams=streams, dem=dem, output=output, cutting_height=cutting_height, snap=snap)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass VerticalExcessCurvature(object):\n    def __init__(self):\n        self.label = \"Vertical Excess Curvature\"\n        self.description = \"This tool calculates vertical excess curvature from an input DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input Raster DEM\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster Image\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        log = arcpy.Parameter(\n            displayName=\"Log-transform the output?\",\n            name=\"log\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        log.value = 'False'\n\n        zfactor = arcpy.Parameter(\n            displayName=\"Z-factor\",\n            name=\"zfactor\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        zfactor.value = '1.0'\n\n        params = [dem, output, log, zfactor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        log = parameters[2].valueAsText\n        zfactor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.vertical_excess_curvature(dem=dem, output=output, log=log, zfactor=zfactor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Viewshed(object):\n    def __init__(self):\n        self.label = \"Viewshed\"\n        self.description = \"Identifies the viewshed for a point or set of points.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        stations = arcpy.Parameter(\n            displayName=\"Viewing Station Vector File\",\n            name=\"stations\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        stations.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        height = arcpy.Parameter(\n            displayName=\"Station Height (in z units)\",\n            name=\"height\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        height.value = '2.0'\n\n        params = [dem, stations, output, height]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        stations = parameters[1].valueAsText\n        if stations is not None:\n            desc = arcpy.Describe(stations)\n            stations = desc.catalogPath\n        output = parameters[2].valueAsText\n        height = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.viewshed(dem=dem, stations=stations, output=output, height=height)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass VisibilityIndex(object):\n    def __init__(self):\n        self.label = \"Visibility Index\"\n        self.description = \"Estimates the relative visibility of sites in a DEM.\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        dem = arcpy.Parameter(\n            displayName=\"Input DEM File\",\n            name=\"dem\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        height = arcpy.Parameter(\n            displayName=\"Station Height (in z units)\",\n            name=\"height\",\n            datatype=\"GPDouble\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        height.value = '2.0'\n\n        res_factor = arcpy.Parameter(\n            displayName=\"Resolution Factor\",\n            name=\"res_factor\",\n            datatype=\"GPLong\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        res_factor.value = '2'\n\n        params = [dem, output, height, res_factor]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        dem = parameters[0].valueAsText\n        if dem is not None:\n            desc = arcpy.Describe(dem)\n            dem = desc.catalogPath\n        output = parameters[1].valueAsText\n        height = parameters[2].valueAsText\n        res_factor = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.visibility_index(dem=dem, output=output, height=height, res_factor=res_factor)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass VoronoiDiagram(object):\n    def __init__(self):\n        self.label = \"Voronoi Diagram\"\n        self.description = \"Creates a vector Voronoi diagram for a set of vector points.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Vector Points File\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Polygon File\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.voronoi_diagram(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Watershed(object):\n    def __init__(self):\n        self.label = \"Watershed\"\n        self.description = \"Identifies the watershed, or drainage basin, draining to a set of target cells.\"\n        self.category = \"Hydrological Analysis\"\n\n    def getParameterInfo(self):\n        d8_pntr = arcpy.Parameter(\n            displayName=\"Input D8 Pointer File\",\n            name=\"d8_pntr\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        pour_pts = arcpy.Parameter(\n            displayName=\"Input Pour Points (Outlet) File\",\n            name=\"pour_pts\",\n            datatype=[\"DERasterDataset\", \"DEShapefile\"],\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        esri_pntr = arcpy.Parameter(\n            displayName=\"Does the pointer file use the ESRI pointer scheme?\",\n            name=\"esri_pntr\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        esri_pntr.value = 'False'\n\n        params = [d8_pntr, pour_pts, output, esri_pntr]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        d8_pntr = parameters[0].valueAsText\n        if d8_pntr is not None:\n            desc = arcpy.Describe(d8_pntr)\n            d8_pntr = desc.catalogPath\n        pour_pts = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        esri_pntr = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.watershed(d8_pntr=d8_pntr, pour_pts=pour_pts, output=output, esri_pntr=esri_pntr)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass WeightedOverlay(object):\n    def __init__(self):\n        self.label = \"Weighted Overlay\"\n        self.description = \"Performs a weighted sum on multiple input rasters after converting each image to a common scale. The tool performs a multi-criteria evaluation (MCE).\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        factors = arcpy.Parameter(\n            displayName=\"Input Factor Files\",\n            name=\"factors\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        factors.multiValue = True\n\n        weights = arcpy.Parameter(\n            displayName=\"Weight Values (e.g. 1.7;3.5;1.2)\",\n            name=\"weights\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        cost = arcpy.Parameter(\n            displayName=\"Cost Factor? (e.g. false;true;true)\",\n            name=\"cost\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        constraints = arcpy.Parameter(\n            displayName=\"Input Constraints Files\",\n            name=\"constraints\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        constraints.multiValue = True\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        scale_max = arcpy.Parameter(\n            displayName=\"Suitability Scale Maximum\",\n            name=\"scale_max\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        scale_max.value = '1.0'\n\n        params = [factors, weights, cost, constraints, output, scale_max]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        factors = parameters[0].valueAsText\n        if factors is not None:\n            items = factors.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            factors = \";\".join(items_path)\n        weights = parameters[1].valueAsText\n        cost = parameters[2].valueAsText\n        constraints = parameters[3].valueAsText\n        if constraints is not None:\n            items = constraints.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            constraints = \";\".join(items_path)\n        output = parameters[4].valueAsText\n        scale_max = parameters[5].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.weighted_overlay(factors=factors, weights=weights, cost=cost, constraints=constraints, output=output, scale_max=scale_max)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass WeightedSum(object):\n    def __init__(self):\n        self.label = \"Weighted Sum\"\n        self.description = \"Performs a weighted-sum overlay on multiple input raster images.\"\n        self.category = \"GIS Analysis\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input Files\",\n            name=\"inputs\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        inputs.multiValue = True\n\n        weights = arcpy.Parameter(\n            displayName=\"Weight Values (e.g. 1.7;3.5;1.2)\",\n            name=\"weights\",\n            datatype=\"GPString\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [inputs, weights, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        weights = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.weighted_sum(inputs=inputs, weights=weights, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass WetnessIndex(object):\n    def __init__(self):\n        self.label = \"Wetness Index\"\n        self.description = \"Calculates the topographic wetness index, Ln(A / tan(slope)).\"\n        self.category = \"Geomorphometric Analysis\"\n\n    def getParameterInfo(self):\n        sca = arcpy.Parameter(\n            displayName=\"Input Specific Contributing Area (SCA) File\",\n            name=\"sca\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        slope = arcpy.Parameter(\n            displayName=\"Input Slope File\",\n            name=\"slope\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [sca, slope, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        sca = parameters[0].valueAsText\n        if sca is not None:\n            desc = arcpy.Describe(sca)\n            sca = desc.catalogPath\n        slope = parameters[1].valueAsText\n        if slope is not None:\n            desc = arcpy.Describe(slope)\n            slope = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.wetness_index(sca=sca, slope=slope, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass WilcoxonSignedRankTest(object):\n    def __init__(self):\n        self.label = \"Wilcoxon Signed Rank Test\"\n        self.description = \"Performs a 2-sample K-S test for significant differences on two input rasters.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"First Input File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Second Input File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"html\"]\n\n        num_samples = arcpy.Parameter(\n            displayName=\"Num. Samples (blank for while image)\",\n            name=\"num_samples\",\n            datatype=\"GPLong\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [input1, input2, output, num_samples]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        num_samples = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.wilcoxon_signed_rank_test(input1=input1, input2=input2, output=output, num_samples=num_samples)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass WriteFunctionMemoryInsertion(object):\n    def __init__(self):\n        self.label = \"Write Function Memory Insertion\"\n        self.description = \"Performs a write function memory insertion for single-band multi-date change detection.\"\n        self.category = \"Image Processing Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"First Date Input File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Second Date Input File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input3 = arcpy.Parameter(\n            displayName=\"Third Date Input File (Optional)\",\n            name=\"input3\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, input3, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        input3 = parameters[2].valueAsText\n        if input3 is not None:\n            desc = arcpy.Describe(input3)\n            input3 = desc.catalogPath\n        output = parameters[3].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.write_function_memory_insertion(input1=input1, input2=input2, input3=input3, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass Xor(object):\n    def __init__(self):\n        self.label = \"Xor\"\n        self.description = \"Performs a logical XOR operator on two Boolean raster images.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        input1 = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"input1\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        input2 = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"input2\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [input1, input2, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        input1 = parameters[0].valueAsText\n        if input1 is not None:\n            desc = arcpy.Describe(input1)\n            input1 = desc.catalogPath\n        input2 = parameters[1].valueAsText\n        if input2 is not None:\n            desc = arcpy.Describe(input2)\n            input2 = desc.catalogPath\n        output = parameters[2].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.xor(input1=input1, input2=input2, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass YieldFilter(object):\n    def __init__(self):\n        self.label = \"Yield Filter\"\n        self.description = \"Filters crop yield values of point data derived from combine harvester yield monitors.\"\n        self.category = \"Precision Agriculture\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Points\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        yield_field = arcpy.Parameter(\n            displayName=\"Yield Field Name\",\n            name=\"yield_field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        yield_field.parameterDependencies = [i.name]\n\n        pass_field = arcpy.Parameter(\n            displayName=\"Pass Field Name\",\n            name=\"pass_field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        pass_field.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Points\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        width = arcpy.Parameter(\n            displayName=\"Swath Width\",\n            name=\"width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        width.value = '6.096'\n\n        z_score_threshold = arcpy.Parameter(\n            displayName=\"Z-score Threshold Value\",\n            name=\"z_score_threshold\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        z_score_threshold.value = '2.5'\n\n        min_yield = arcpy.Parameter(\n            displayName=\"Minimum Yield\",\n            name=\"min_yield\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_yield.value = '0.0'\n\n        max_yield = arcpy.Parameter(\n            displayName=\"Maximum Yield\",\n            name=\"max_yield\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_yield.value = '99999.9'\n\n        params = [i, yield_field, pass_field, output, width, z_score_threshold, min_yield, max_yield]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        yield_field = parameters[1].valueAsText\n        pass_field = parameters[2].valueAsText\n        output = parameters[3].valueAsText\n        width = parameters[4].valueAsText\n        z_score_threshold = parameters[5].valueAsText\n        min_yield = parameters[6].valueAsText\n        max_yield = parameters[7].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.yield_filter(i=i, yield_field=yield_field, pass_field=pass_field, output=output, width=width, z_score_threshold=z_score_threshold, min_yield=min_yield, max_yield=max_yield)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass YieldMap(object):\n    def __init__(self):\n        self.label = \"Yield Map\"\n        self.description = \"This tool can be used to create a segmented-vector polygon yield map from a set of harvester points.\"\n        self.category = \"Precision Agriculture\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Points\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        pass_field_name = arcpy.Parameter(\n            displayName=\"Pass Field Name\",\n            name=\"pass_field_name\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        pass_field_name.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Vector Polygons\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        width = arcpy.Parameter(\n            displayName=\"Swath Width\",\n            name=\"width\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        width.value = '6.096'\n\n        max_change_in_heading = arcpy.Parameter(\n            displayName=\"Max Change In Heading (degrees)\",\n            name=\"max_change_in_heading\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_change_in_heading.value = '25.0'\n\n        params = [i, pass_field_name, output, width, max_change_in_heading]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        pass_field_name = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        width = parameters[3].valueAsText\n        max_change_in_heading = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.yield_map(i=i, pass_field_name=pass_field_name, output=output, width=width, max_change_in_heading=max_change_in_heading)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass YieldNormalization(object):\n    def __init__(self):\n        self.label = \"Yield Normalization\"\n        self.description = \"This tool can be used to normalize the yield points for a field.\"\n        self.category = \"Precision Agriculture\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Points\",\n            name=\"i\",\n            datatype=\"GPFeatureLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        i.filter.list = [\"Point\"]\n\n        yield_field = arcpy.Parameter(\n            displayName=\"Yield Field Name\",\n            name=\"yield_field\",\n            datatype=\"Field\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n        yield_field.parameterDependencies = [i.name]\n\n        output = arcpy.Parameter(\n            displayName=\"Output Points\",\n            name=\"output\",\n            datatype=\"DEShapefile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n\n        standardize = arcpy.Parameter(\n            displayName=\"Standardize rather than normalize?\",\n            name=\"standardize\",\n            datatype=\"GPBoolean\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        standardize.value = 'False'\n\n        radius = arcpy.Parameter(\n            displayName=\"Search Radius (m)\",\n            name=\"radius\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        min_yield = arcpy.Parameter(\n            displayName=\"Minimum Yield\",\n            name=\"min_yield\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        min_yield.value = '0.0'\n\n        max_yield = arcpy.Parameter(\n            displayName=\"Maximum Yield\",\n            name=\"max_yield\",\n            datatype=\"GPDouble\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        max_yield.value = '99999.9'\n\n        params = [i, yield_field, output, standardize, radius, min_yield, max_yield]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        yield_field = parameters[1].valueAsText\n        output = parameters[2].valueAsText\n        standardize = parameters[3].valueAsText\n        radius = parameters[4].valueAsText\n        min_yield = parameters[5].valueAsText\n        max_yield = parameters[6].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.yield_normalization(i=i, yield_field=yield_field, output=output, standardize=standardize, radius=radius, min_yield=min_yield, max_yield=max_yield)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ZScores(object):\n    def __init__(self):\n        self.label = \"Z Scores\"\n        self.description = \"Standardizes the values in an input raster by converting to z-scores.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        params = [i, output]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        output = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.z_scores(i=i, output=output)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ZlidarToLas(object):\n    def __init__(self):\n        self.label = \"Zlidar To Las\"\n        self.description = \"Converts one or more zlidar files into the LAS data format.\"\n        self.category = \"LiDAR Tools\"\n\n    def getParameterInfo(self):\n        inputs = arcpy.Parameter(\n            displayName=\"Input ZLidar Files\",\n            name=\"inputs\",\n            datatype=\"DEFile\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        inputs.multiValue = True\n        inputs.filter.list = [\"las\", \"zip\"]\n\n        outdir = arcpy.Parameter(\n            displayName=\"Output Directory\",\n            name=\"outdir\",\n            datatype=\"DEFolder\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n\n        params = [inputs, outdir]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        inputs = parameters[0].valueAsText\n        if inputs is not None:\n            items = inputs.split(\";\")\n            items_path = []\n            for item in items:\n                items_path.append(arcpy.Describe(item).catalogPath)\n            inputs = \";\".join(items_path)\n        outdir = parameters[1].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.zlidar_to_las(inputs=inputs, outdir=outdir)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\nclass ZonalStatistics(object):\n    def __init__(self):\n        self.label = \"Zonal Statistics\"\n        self.description = \"Extracts descriptive statistics for a group of patches in a raster.\"\n        self.category = \"Math and Stats Tools\"\n\n    def getParameterInfo(self):\n        i = arcpy.Parameter(\n            displayName=\"Input Data File\",\n            name=\"i\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        features = arcpy.Parameter(\n            displayName=\"Input Feature Definition File\",\n            name=\"features\",\n            datatype=\"GPRasterLayer\",\n            parameterType=\"Required\",\n            direction=\"Input\")\n\n        output = arcpy.Parameter(\n            displayName=\"Output Raster File\",\n            name=\"output\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        output.filter.list = [\"tif\"]\n\n        stat = arcpy.Parameter(\n            displayName=\"Statistic Type\",\n            name=\"stat\",\n            datatype=\"GPString\",\n            parameterType=\"Optional\",\n            direction=\"Input\")\n        stat.filter.type = \"ValueList\"\n        stat.filter.list = ['mean', 'median', 'minimum', 'maximum', 'range', 'standard deviation', 'total']\n        stat.value = 'mean'\n\n        out_table = arcpy.Parameter(\n            displayName=\"Output HTML Table File\",\n            name=\"out_table\",\n            datatype=\"DEFile\",\n            parameterType=\"Required\",\n            direction=\"Output\")\n        out_table.filter.list = [\"html\"]\n\n        params = [i, features, output, stat, out_table]\n\n        return params\n\n    def updateParameters(self, parameters):\n        return\n\n    def updateMessages(self, parameters):\n        for param in parameters:\n            param_str = param.valueAsText\n            if param_str is not None:\n                try:\n                    desc = arcpy.Describe(param_str)\n                    if (\".gdb\\\\\" in desc.catalogPath) or (\".mdb\\\\\" in desc.catalogPath):\n                        param.setErrorMessage(\"Datasets stored in a Geodatabase are not supported.\")\n                except:\n                    param.clearMessage()\n        return\n\n    def execute(self, parameters, messages):\n        i = parameters[0].valueAsText\n        if i is not None:\n            desc = arcpy.Describe(i)\n            i = desc.catalogPath\n        features = parameters[1].valueAsText\n        if features is not None:\n            desc = arcpy.Describe(features)\n            features = desc.catalogPath\n        output = parameters[2].valueAsText\n        stat = parameters[3].valueAsText\n        out_table = parameters[4].valueAsText\n        old_stdout = sys.stdout\n        result = StringIO()\n        sys.stdout = result\n        wbt.zonal_statistics(i=i, features=features, output=output, stat=stat, out_table=out_table)\n        sys.stdout = old_stdout\n        result_string = result.getvalue()\n        messages.addMessage(result_string)\n        return\n\n\n"
  },
  {
    "path": "testdata/DEM/DEM.dep",
    "content": "Min:\t212.22877502441406\nMax:\t1233.0966796875\nNorth:\t4895782.5891085025\nSouth:\t4878858.5400943495\nEast:\t686063.139196986\nWest:\t664737.0507251581\nCols:\t237\nRows:\t188\nStacks:\t1\nData Type:\tFLOAT\nZ Units:\tnot specified\nXY Units:\tmetres\nProjection:\tnot specified\nData Scale:\tcontinuous\nDisplay Min:\t212.22877502441406\nDisplay Max:\t1233.0966796875\nPreferred Palette:\thigh_relief.pal\nNoData:\t-32768.0\nByte Order:\tLITTLE_ENDIAN\nPalette Nonlinearity:\t1.0\n"
  },
  {
    "path": "testdata/Landsat/LC80320272014265LGN00_Boundary.cpg",
    "content": "UTF-8"
  },
  {
    "path": "testdata/Landsat/LC80320272014265LGN00_Boundary.prj",
    "content": "PROJCS[\"NAD_1983_UTM_Zone_14N\",GEOGCS[\"GCS_North_American_1983\",DATUM[\"D_North_American_1983\",SPHEROID[\"GRS_1980\",6378137.0,298.257222101]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"False_Easting\",500000.0],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",-99.0],PARAMETER[\"Scale_Factor\",0.9996],PARAMETER[\"Latitude_Of_Origin\",0.0],UNIT[\"Meter\",1.0]]"
  },
  {
    "path": "testdata/Landsat/Readme.txt",
    "content": "Landsat 8 scene id: LC80320272014265LGN00\nAcquisition Date: 2014-09-22\nCoverage area: Central North Dakota\n \nDownloaded from https://libra.developmentseed.org/\n\nB1 - Coastal aerosol\nB2 - Blue\nB3 - Green \nB4 - Red\nB5 - Near Infrared\nB6 - Shortwave Infrared 1\nB7 - Shortwave Infrared 2\nB8 - Panchromatic\n"
  },
  {
    "path": "testdata/Wetlands/CLSA_Boundary.prj",
    "content": "PROJCS[\"NAD_1983_UTM_Zone_14N\",GEOGCS[\"GCS_North_American_1983\",DATUM[\"D_North_American_1983\",SPHEROID[\"GRS_1980\",6378137.0,298.257222101]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"False_Easting\",500000.0],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",-99.0],PARAMETER[\"Scale_Factor\",0.9996],PARAMETER[\"Latitude_Of_Origin\",0.0],UNIT[\"Meter\",1.0]]"
  },
  {
    "path": "testdata/Wetlands/CLSA_Wetland_Points.prj",
    "content": "PROJCS[\"NAD_1983_UTM_Zone_14N\",GEOGCS[\"GCS_North_American_1983\",DATUM[\"D_North_American_1983\",SPHEROID[\"GRS_1980\",6378137.0,298.257222101]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"False_Easting\",500000.0],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",-99.0],PARAMETER[\"Scale_Factor\",0.9996],PARAMETER[\"Latitude_Of_Origin\",0.0],UNIT[\"Meter\",1.0]]"
  },
  {
    "path": "testdata/Wetlands/CLSA_Wetland_Polygons.prj",
    "content": "PROJCS[\"NAD_1983_UTM_Zone_14N\",GEOGCS[\"GCS_North_American_1983\",DATUM[\"D_North_American_1983\",SPHEROID[\"GRS_1980\",6378137.0,298.257222101]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"False_Easting\",500000.0],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",-99.0],PARAMETER[\"Scale_Factor\",0.9996],PARAMETER[\"Latitude_Of_Origin\",0.0],UNIT[\"Meter\",1.0]]"
  },
  {
    "path": "testdata/Wetlands/CLSA_Wetland_Polylines.cpg",
    "content": "UTF-8"
  },
  {
    "path": "testdata/Wetlands/CLSA_Wetland_Polylines.prj",
    "content": "PROJCS[\"NAD_1983_UTM_Zone_14N\",GEOGCS[\"GCS_North_American_1983\",DATUM[\"D_North_American_1983\",SPHEROID[\"GRS_1980\",6378137.0,298.257222101]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"False_Easting\",500000.0],PARAMETER[\"False_Northing\",0.0],PARAMETER[\"Central_Meridian\",-99.0],PARAMETER[\"Scale_Factor\",0.9996],PARAMETER[\"Latitude_Of_Origin\",0.0],UNIT[\"Meter\",1.0]]"
  },
  {
    "path": "testdata/Wetlands/Readme.txt",
    "content": "Cottonwood Lake Study Area(CLSA), Stutsman County, North Dakota.\n\nMore info at: https://dx.doi.org/10.5066/F7707ZJ6\n"
  },
  {
    "path": "testdata/WorldMap/Readme.txt",
    "content": "TM_WORLD_BORDERS-0.1.ZIP \r\n\r\nProvided by Bjorn Sandvik, thematicmapping.org\r\n\r\nUse this dataset with care, as several of the borders are disputed.\r\n\r\nThe original shapefile (world_borders.zip, 3.2 MB) was downloaded from the Mapping Hacks website:\r\nhttp://www.mappinghacks.com/data/\r\n\r\nThe dataset was derived by Schuyler Erle from public domain sources.\r\nSean Gilles did some clean up and made some enhancements.\r\n\r\n\r\nCOLUMN\t\tTYPE\t\t\tDESCRIPTION\r\n\r\nShape\t\tPolygon\t\t\tCountry/area border as polygon(s)\r\nFIPS\t\tString(2)\t\tFIPS 10-4 Country Code\r\nISO2\t\tString(2)\t\tISO 3166-1 Alpha-2 Country Code\r\nISO3\t\tString(3)\t\tISO 3166-1 Alpha-3 Country Code\r\nUN\t\tShort Integer(3)\tISO 3166-1 Numeric-3 Country Code \r\nNAME\t\tString(50)\t\tName of country/area\r\nAREA\t\tLong Integer(7)\t\tLand area, FAO Statistics (2002) \r\nPOP2005\t\tDouble(10,0)\t \tPopulation, World Polulation Prospects (2005)\r\nREGION\t\tShort Integer(3) \tMacro geographical (continental region), UN Statistics\r\nSUBREGION\tShort Integer(3)\tGeogrpahical sub-region, UN Statistics\r\nLON\t\tFLOAT (7,3)\t\tLongitude\r\nLAT\t\tFLOAT (6,3)\t\tLatitude\r\n\r\n\r\nCHANGELOG VERSION 0.3 - 30 July 2008\r\n\r\n- Corrected spelling mistake (United Arab Emirates)\r\n- Corrected population number for Japan\r\n- Adjusted long/lat values for India, Italy and United Kingdom\r\n\r\n\r\nCHANGELOG VERSION 0.2 - 1 April 2008\r\n\r\n- Made new ZIP archieves. No change in dataset.\r\n\r\n\r\nCHANGELOG VERSION 0.1 - 13 March 2008\r\n\r\n- Polygons representing each country were merged into one feature\r\n- land Islands was extracted from Finland\r\n- Hong Kong was extracted from China\r\n- Holy See (Vatican City) was added\r\n- Gaza Strip and West Bank was merged into \"Occupied Palestinean Territory\"\r\n- Saint-Barthelemy was extracted from Netherlands Antilles\r\n- Saint-Martin (Frensh part) was extracted from Guadeloupe\r\n- Svalbard and Jan Mayen was merged into \"Svalbard and Jan Mayen Islands\"\r\n- Timor-Leste was extracted from Indonesia\r\n- Juan De Nova Island was merged with \"French Southern & Antarctic Land\"\r\n- Baker Island, Howland Island, Jarvis Island, Johnston Atoll, Midway Islands\r\n  and Wake Island was merged into \"United States Minor Outlying Islands\"\r\n- Glorioso Islands, Parcel Islands, Spartly Islands was removed \r\n  (almost uninhabited and missing ISO-3611-1 code)\r\n\r\n- Added ISO-3166-1 codes (alpha-2, alpha-3, numeric-3). Source:\r\n  https://www.cia.gov/library/publications/the-world-factbook/appendix/appendix-d.html\r\n  http://unstats.un.org/unsd/methods/m49/m49alpha.htm\r\n  http://www.fysh.org/~katie/development/geography.txt\r\n- AREA column has been replaced with data from UNdata:\r\n  Land area, 1000 hectares, 2002, FAO Statistics\r\n- POPULATION column (POP2005) has been replaced with data from UNdata:\r\n  Population, 2005, Medium variant, World Population Prospects: The 2006 Revision\r\n- Added region and sub-region codes from UN Statistics Division. Source:\r\n  http://unstats.un.org/unsd/methods/m49/m49regin.htm\r\n- Added LAT, LONG values for each country\r\n\r\n"
  },
  {
    "path": "testdata/WorldMap/TM_WORLD_BORDERS_SIMPL-0.3.prj",
    "content": "GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]]"
  },
  {
    "path": "testdata/examples.py",
    "content": "import os\r\n# import arcpy\r\n\r\ndata_dir = os.path.dirname(os.path.abspath(__file__))\r\nwbt_dir = os.path.dirname(data_dir)\r\nout_dir = os.path.join(os.path.expanduser(\"~\"), \"temp\")\r\n\r\nif not os.path.exists(out_dir):\r\n    os.makedirs(out_dir)\r\n\r\ntbx = os.path.join(wbt_dir, \"WhiteboxTools.pyt\")\r\narcpy.ImportToolbox(tbx)\r\n\r\ninput = os.path.join(data_dir, \"Wetlands\\CLSA_Wetland_Polygons.shp\")\r\noutput = os.path.join(out_dir, \"test.tif\")\r\narcpy.VectorPolygonsToRaster_WBT(input, \"FID\", output, cell_size=10)\r\nprint(\"Results saved at: {}\".format(output))"
  }
]